11use std:: cell:: RefCell ;
22use std:: collections:: BTreeMap ;
3- use std:: marker:: PhantomData ;
43use std:: ops:: { Deref , DerefMut } ;
54use std:: sync:: LazyLock ;
65
@@ -180,7 +179,11 @@ pub trait Stage: Sized + 'static + Sealed {
180179
181180 fn parsers ( ) -> & ' static group_type ! ( Self ) ;
182181
183- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed ;
182+ fn emit_err < ' sess > (
183+ & self ,
184+ sess : & ' sess Session ,
185+ diag : impl for < ' x > Diagnostic < ' x > ,
186+ ) -> ErrorGuaranteed ;
184187}
185188
186189// allow because it's a sealed trait
@@ -192,8 +195,16 @@ impl Stage for Early {
192195 fn parsers ( ) -> & ' static group_type ! ( Self ) {
193196 & early:: ATTRIBUTE_PARSERS
194197 }
195- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
196- sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
198+ fn emit_err < ' sess > (
199+ & self ,
200+ sess : & ' sess Session ,
201+ diag : impl for < ' x > Diagnostic < ' x > ,
202+ ) -> ErrorGuaranteed {
203+ if self . emit_errors {
204+ sess. dcx ( ) . emit_err ( diag)
205+ } else {
206+ sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
207+ }
197208 }
198209}
199210
@@ -206,20 +217,29 @@ impl Stage for Late {
206217 fn parsers ( ) -> & ' static group_type ! ( Self ) {
207218 & late:: ATTRIBUTE_PARSERS
208219 }
209- fn emit_err < ' sess > ( tcx : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
220+ fn emit_err < ' sess > (
221+ & self ,
222+ tcx : & ' sess Session ,
223+ diag : impl for < ' x > Diagnostic < ' x > ,
224+ ) -> ErrorGuaranteed {
210225 tcx. dcx ( ) . emit_err ( diag)
211226 }
212227}
213228
214229/// used when parsing attributes for miscellaneous things *before* ast lowering
215- pub struct Early ;
230+ pub struct Early {
231+ /// Whether to emit errors or delay them as a bug
232+ /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
233+ /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
234+ pub emit_errors : bool ,
235+ }
216236/// used when parsing attributes during ast lowering
217237pub struct Late ;
218238
219239/// Context given to every attribute parser when accepting
220240///
221241/// Gives [`AttributeParser`]s enough information to create errors, for example.
222- pub ( crate ) struct AcceptContext < ' f , ' sess , S : Stage > {
242+ pub struct AcceptContext < ' f , ' sess , S : Stage > {
223243 pub ( crate ) shared : SharedContext < ' f , ' sess , S > ,
224244 /// The span of the attribute currently being parsed
225245 pub ( crate ) attr_span : Span ,
@@ -235,7 +255,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
235255
236256impl < ' f , ' sess : ' f , S : Stage > SharedContext < ' f , ' sess , S > {
237257 pub ( crate ) fn emit_err ( & self , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
238- S :: emit_err ( & self . sess , diag)
258+ self . stage . emit_err ( & self . sess , diag)
239259 }
240260
241261 /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -450,7 +470,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
450470///
451471/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
452472/// errors, for example.
453- pub ( crate ) struct SharedContext < ' p , ' sess , S : Stage > {
473+ pub struct SharedContext < ' p , ' sess , S : Stage > {
454474 /// The parse context, gives access to the session and the
455475 /// diagnostics context.
456476 pub ( crate ) cx : & ' p mut AttributeParser < ' sess , S > ,
@@ -518,7 +538,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
518538 pub ( crate ) tools : Vec < Symbol > ,
519539 features : Option < & ' sess Features > ,
520540 sess : & ' sess Session ,
521- stage : PhantomData < S > ,
541+ stage : S ,
522542
523543 /// *Only* parse attributes with this symbol.
524544 ///
@@ -547,13 +567,14 @@ impl<'sess> AttributeParser<'sess, Early> {
547567 sym : Symbol ,
548568 target_span : Span ,
549569 target_node_id : NodeId ,
570+ features : Option < & ' sess Features > ,
550571 ) -> Option < Attribute > {
551572 let mut p = Self {
552- features : None ,
573+ features,
553574 tools : Vec :: new ( ) ,
554575 parse_only : Some ( sym) ,
555576 sess,
556- stage : PhantomData ,
577+ stage : Early { emit_errors : false } ,
557578 } ;
558579 let mut parsed = p. parse_attribute_list (
559580 attrs,
@@ -569,11 +590,55 @@ impl<'sess> AttributeParser<'sess, Early> {
569590
570591 parsed. pop ( )
571592 }
593+
594+ pub fn parse_single < T > (
595+ sess : & ' sess Session ,
596+ attr : & ast:: Attribute ,
597+ target_span : Span ,
598+ target_node_id : NodeId ,
599+ features : Option < & ' sess Features > ,
600+ emit_errors : bool ,
601+ parse_fn : fn ( cx : & mut AcceptContext < ' _ , ' _ , Early > , item : & ArgParser < ' _ > ) -> T ,
602+ template : & AttributeTemplate ,
603+ ) -> T {
604+ let mut parser = Self {
605+ features,
606+ tools : Vec :: new ( ) ,
607+ parse_only : None ,
608+ sess,
609+ stage : Early { emit_errors } ,
610+ } ;
611+ let ast:: AttrKind :: Normal ( normal_attr) = & attr. kind else {
612+ panic ! ( "parse_single called on a doc attr" )
613+ } ;
614+ let meta_parser = MetaItemParser :: from_attr ( normal_attr, parser. dcx ( ) ) ;
615+ let path = meta_parser. path ( ) ;
616+ let args = meta_parser. args ( ) ;
617+ let mut cx: AcceptContext < ' _ , ' sess , Early > = AcceptContext {
618+ shared : SharedContext {
619+ cx : & mut parser,
620+ target_span,
621+ target_id : target_node_id,
622+ emit_lint : & mut |_lint| {
623+ panic ! ( "can't emit lints here for now (nothing uses this atm)" ) ;
624+ } ,
625+ } ,
626+ attr_span : attr. span ,
627+ template,
628+ attr_path : path. get_attribute_path ( ) ,
629+ } ;
630+ parse_fn ( & mut cx, args)
631+ }
572632}
573633
574634impl < ' sess , S : Stage > AttributeParser < ' sess , S > {
575- pub fn new ( sess : & ' sess Session , features : & ' sess Features , tools : Vec < Symbol > ) -> Self {
576- Self { features : Some ( features) , tools, parse_only : None , sess, stage : PhantomData }
635+ pub fn new (
636+ sess : & ' sess Session ,
637+ features : & ' sess Features ,
638+ tools : Vec < Symbol > ,
639+ stage : S ,
640+ ) -> Self {
641+ Self { features : Some ( features) , tools, parse_only : None , sess, stage }
577642 }
578643
579644 pub ( crate ) fn sess ( & self ) -> & ' sess Session {
@@ -584,6 +649,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
584649 self . features . expect ( "features not available at this point in the compiler" )
585650 }
586651
652+ pub ( crate ) fn features_option ( & self ) -> Option < & ' sess Features > {
653+ self . features
654+ }
655+
587656 pub ( crate ) fn dcx ( & self ) -> DiagCtxtHandle < ' sess > {
588657 self . sess ( ) . dcx ( )
589658 }
0 commit comments