11use std:: cell:: RefCell ;
22use std:: collections:: BTreeMap ;
3- use std:: marker:: PhantomData ;
43use std:: ops:: { Deref , DerefMut } ;
54use std:: sync:: LazyLock ;
65
@@ -202,7 +201,11 @@ pub trait Stage: Sized + 'static + Sealed {
202201
203202 fn parsers ( ) -> & ' static group_type ! ( Self ) ;
204203
205- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed ;
204+ fn emit_err < ' sess > (
205+ & self ,
206+ sess : & ' sess Session ,
207+ diag : impl for < ' x > Diagnostic < ' x > ,
208+ ) -> ErrorGuaranteed ;
206209}
207210
208211// allow because it's a sealed trait
@@ -214,8 +217,16 @@ impl Stage for Early {
214217 fn parsers ( ) -> & ' static group_type ! ( Self ) {
215218 & early:: ATTRIBUTE_PARSERS
216219 }
217- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
218- sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
220+ fn emit_err < ' sess > (
221+ & self ,
222+ sess : & ' sess Session ,
223+ diag : impl for < ' x > Diagnostic < ' x > ,
224+ ) -> ErrorGuaranteed {
225+ if self . emit_errors {
226+ sess. dcx ( ) . emit_err ( diag)
227+ } else {
228+ sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
229+ }
219230 }
220231}
221232
@@ -228,20 +239,29 @@ impl Stage for Late {
228239 fn parsers ( ) -> & ' static group_type ! ( Self ) {
229240 & late:: ATTRIBUTE_PARSERS
230241 }
231- fn emit_err < ' sess > ( tcx : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
242+ fn emit_err < ' sess > (
243+ & self ,
244+ tcx : & ' sess Session ,
245+ diag : impl for < ' x > Diagnostic < ' x > ,
246+ ) -> ErrorGuaranteed {
232247 tcx. dcx ( ) . emit_err ( diag)
233248 }
234249}
235250
236251/// used when parsing attributes for miscellaneous things *before* ast lowering
237- pub struct Early ;
252+ pub struct Early {
253+ /// Whether to emit errors or delay them as a bug
254+ /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
255+ /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
256+ pub emit_errors : bool ,
257+ }
238258/// used when parsing attributes during ast lowering
239259pub struct Late ;
240260
241261/// Context given to every attribute parser when accepting
242262///
243263/// Gives [`AttributeParser`]s enough information to create errors, for example.
244- pub ( crate ) struct AcceptContext < ' f , ' sess , S : Stage > {
264+ pub struct AcceptContext < ' f , ' sess , S : Stage > {
245265 pub ( crate ) shared : SharedContext < ' f , ' sess , S > ,
246266 /// The span of the attribute currently being parsed
247267 pub ( crate ) attr_span : Span ,
@@ -257,7 +277,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
257277
258278impl < ' f , ' sess : ' f , S : Stage > SharedContext < ' f , ' sess , S > {
259279 pub ( crate ) fn emit_err ( & self , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
260- S :: emit_err ( & self . sess , diag)
280+ self . stage . emit_err ( & self . sess , diag)
261281 }
262282
263283 /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -472,7 +492,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
472492///
473493/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
474494/// errors, for example.
475- pub ( crate ) struct SharedContext < ' p , ' sess , S : Stage > {
495+ pub struct SharedContext < ' p , ' sess , S : Stage > {
476496 /// The parse context, gives access to the session and the
477497 /// diagnostics context.
478498 pub ( crate ) cx : & ' p mut AttributeParser < ' sess , S > ,
@@ -540,7 +560,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
540560 pub ( crate ) tools : Vec < Symbol > ,
541561 features : Option < & ' sess Features > ,
542562 sess : & ' sess Session ,
543- stage : PhantomData < S > ,
563+ stage : S ,
544564
545565 /// *Only* parse attributes with this symbol.
546566 ///
@@ -569,13 +589,14 @@ impl<'sess> AttributeParser<'sess, Early> {
569589 sym : Symbol ,
570590 target_span : Span ,
571591 target_node_id : NodeId ,
592+ features : Option < & ' sess Features > ,
572593 ) -> Option < Attribute > {
573594 let mut p = Self {
574- features : None ,
595+ features,
575596 tools : Vec :: new ( ) ,
576597 parse_only : Some ( sym) ,
577598 sess,
578- stage : PhantomData ,
599+ stage : Early { emit_errors : false } ,
579600 } ;
580601 let mut parsed = p. parse_attribute_list (
581602 attrs,
@@ -591,11 +612,55 @@ impl<'sess> AttributeParser<'sess, Early> {
591612
592613 parsed. pop ( )
593614 }
615+
616+ pub fn parse_single < T > (
617+ sess : & ' sess Session ,
618+ attr : & ast:: Attribute ,
619+ target_span : Span ,
620+ target_node_id : NodeId ,
621+ features : Option < & ' sess Features > ,
622+ emit_errors : bool ,
623+ parse_fn : fn ( cx : & mut AcceptContext < ' _ , ' _ , Early > , item : & ArgParser < ' _ > ) -> T ,
624+ template : & AttributeTemplate ,
625+ ) -> T {
626+ let mut parser = Self {
627+ features,
628+ tools : Vec :: new ( ) ,
629+ parse_only : None ,
630+ sess,
631+ stage : Early { emit_errors } ,
632+ } ;
633+ let ast:: AttrKind :: Normal ( normal_attr) = & attr. kind else {
634+ panic ! ( "parse_single called on a doc attr" )
635+ } ;
636+ let meta_parser = MetaItemParser :: from_attr ( normal_attr, parser. dcx ( ) ) ;
637+ let path = meta_parser. path ( ) ;
638+ let args = meta_parser. args ( ) ;
639+ let mut cx: AcceptContext < ' _ , ' sess , Early > = AcceptContext {
640+ shared : SharedContext {
641+ cx : & mut parser,
642+ target_span,
643+ target_id : target_node_id,
644+ emit_lint : & mut |_lint| {
645+ panic ! ( "can't emit lints here for now (nothing uses this atm)" ) ;
646+ } ,
647+ } ,
648+ attr_span : attr. span ,
649+ template,
650+ attr_path : path. get_attribute_path ( ) ,
651+ } ;
652+ parse_fn ( & mut cx, args)
653+ }
594654}
595655
596656impl < ' sess , S : Stage > AttributeParser < ' sess , S > {
597- pub fn new ( sess : & ' sess Session , features : & ' sess Features , tools : Vec < Symbol > ) -> Self {
598- Self { features : Some ( features) , tools, parse_only : None , sess, stage : PhantomData }
657+ pub fn new (
658+ sess : & ' sess Session ,
659+ features : & ' sess Features ,
660+ tools : Vec < Symbol > ,
661+ stage : S ,
662+ ) -> Self {
663+ Self { features : Some ( features) , tools, parse_only : None , sess, stage }
599664 }
600665
601666 pub ( crate ) fn sess ( & self ) -> & ' sess Session {
@@ -606,6 +671,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
606671 self . features . expect ( "features not available at this point in the compiler" )
607672 }
608673
674+ pub ( crate ) fn features_option ( & self ) -> Option < & ' sess Features > {
675+ self . features
676+ }
677+
609678 pub ( crate ) fn dcx ( & self ) -> DiagCtxtHandle < ' sess > {
610679 self . sess ( ) . dcx ( )
611680 }
0 commit comments