11use std:: cell:: RefCell ;
22use std:: collections:: BTreeMap ;
3- use std:: marker:: PhantomData ;
43use std:: ops:: { Deref , DerefMut } ;
54use std:: sync:: LazyLock ;
65
@@ -200,7 +199,11 @@ pub trait Stage: Sized + 'static + Sealed {
200199
201200 fn parsers ( ) -> & ' static group_type ! ( Self ) ;
202201
203- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed ;
202+ fn emit_err < ' sess > (
203+ & self ,
204+ sess : & ' sess Session ,
205+ diag : impl for < ' x > Diagnostic < ' x > ,
206+ ) -> ErrorGuaranteed ;
204207}
205208
206209// allow because it's a sealed trait
@@ -212,8 +215,16 @@ impl Stage for Early {
212215 fn parsers ( ) -> & ' static group_type ! ( Self ) {
213216 & early:: ATTRIBUTE_PARSERS
214217 }
215- fn emit_err < ' sess > ( sess : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
216- sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
218+ fn emit_err < ' sess > (
219+ & self ,
220+ sess : & ' sess Session ,
221+ diag : impl for < ' x > Diagnostic < ' x > ,
222+ ) -> ErrorGuaranteed {
223+ if self . emit_errors {
224+ sess. dcx ( ) . emit_err ( diag)
225+ } else {
226+ sess. dcx ( ) . create_err ( diag) . delay_as_bug ( )
227+ }
217228 }
218229}
219230
@@ -226,20 +237,29 @@ impl Stage for Late {
226237 fn parsers ( ) -> & ' static group_type ! ( Self ) {
227238 & late:: ATTRIBUTE_PARSERS
228239 }
229- fn emit_err < ' sess > ( tcx : & ' sess Session , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
240+ fn emit_err < ' sess > (
241+ & self ,
242+ tcx : & ' sess Session ,
243+ diag : impl for < ' x > Diagnostic < ' x > ,
244+ ) -> ErrorGuaranteed {
230245 tcx. dcx ( ) . emit_err ( diag)
231246 }
232247}
233248
234249/// used when parsing attributes for miscellaneous things *before* ast lowering
235- pub struct Early ;
250+ pub struct Early {
251+ /// Whether to emit errors or delay them as a bug
252+ /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
253+ /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
254+ pub emit_errors : bool ,
255+ }
236256/// used when parsing attributes during ast lowering
237257pub struct Late ;
238258
239259/// Context given to every attribute parser when accepting
240260///
241261/// Gives [`AttributeParser`]s enough information to create errors, for example.
242- pub ( crate ) struct AcceptContext < ' f , ' sess , S : Stage > {
262+ pub struct AcceptContext < ' f , ' sess , S : Stage > {
243263 pub ( crate ) shared : SharedContext < ' f , ' sess , S > ,
244264 /// The span of the attribute currently being parsed
245265 pub ( crate ) attr_span : Span ,
@@ -255,7 +275,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
255275
256276impl < ' f , ' sess : ' f , S : Stage > SharedContext < ' f , ' sess , S > {
257277 pub ( crate ) fn emit_err ( & self , diag : impl for < ' x > Diagnostic < ' x > ) -> ErrorGuaranteed {
258- S :: emit_err ( & self . sess , diag)
278+ self . stage . emit_err ( & self . sess , diag)
259279 }
260280
261281 /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -470,7 +490,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
470490///
471491/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
472492/// errors, for example.
473- pub ( crate ) struct SharedContext < ' p , ' sess , S : Stage > {
493+ pub struct SharedContext < ' p , ' sess , S : Stage > {
474494 /// The parse context, gives access to the session and the
475495 /// diagnostics context.
476496 pub ( crate ) cx : & ' p mut AttributeParser < ' sess , S > ,
@@ -538,7 +558,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
538558 pub ( crate ) tools : Vec < Symbol > ,
539559 features : Option < & ' sess Features > ,
540560 sess : & ' sess Session ,
541- stage : PhantomData < S > ,
561+ stage : S ,
542562
543563 /// *Only* parse attributes with this symbol.
544564 ///
@@ -567,13 +587,14 @@ impl<'sess> AttributeParser<'sess, Early> {
567587 sym : Symbol ,
568588 target_span : Span ,
569589 target_node_id : NodeId ,
590+ features : Option < & ' sess Features > ,
570591 ) -> Option < Attribute > {
571592 let mut p = Self {
572- features : None ,
593+ features,
573594 tools : Vec :: new ( ) ,
574595 parse_only : Some ( sym) ,
575596 sess,
576- stage : PhantomData ,
597+ stage : Early { emit_errors : false } ,
577598 } ;
578599 let mut parsed = p. parse_attribute_list (
579600 attrs,
@@ -589,11 +610,55 @@ impl<'sess> AttributeParser<'sess, Early> {
589610
590611 parsed. pop ( )
591612 }
613+
614+ pub fn parse_single < T > (
615+ sess : & ' sess Session ,
616+ attr : & ast:: Attribute ,
617+ target_span : Span ,
618+ target_node_id : NodeId ,
619+ features : Option < & ' sess Features > ,
620+ emit_errors : bool ,
621+ parse_fn : fn ( cx : & mut AcceptContext < ' _ , ' _ , Early > , item : & ArgParser < ' _ > ) -> T ,
622+ template : & AttributeTemplate ,
623+ ) -> T {
624+ let mut parser = Self {
625+ features,
626+ tools : Vec :: new ( ) ,
627+ parse_only : None ,
628+ sess,
629+ stage : Early { emit_errors } ,
630+ } ;
631+ let ast:: AttrKind :: Normal ( normal_attr) = & attr. kind else {
632+ panic ! ( "parse_single called on a doc attr" )
633+ } ;
634+ let meta_parser = MetaItemParser :: from_attr ( normal_attr, parser. dcx ( ) ) ;
635+ let path = meta_parser. path ( ) ;
636+ let args = meta_parser. args ( ) ;
637+ let mut cx: AcceptContext < ' _ , ' sess , Early > = AcceptContext {
638+ shared : SharedContext {
639+ cx : & mut parser,
640+ target_span,
641+ target_id : target_node_id,
642+ emit_lint : & mut |_lint| {
643+ panic ! ( "can't emit lints here for now (nothing uses this atm)" ) ;
644+ } ,
645+ } ,
646+ attr_span : attr. span ,
647+ template,
648+ attr_path : path. get_attribute_path ( ) ,
649+ } ;
650+ parse_fn ( & mut cx, args)
651+ }
592652}
593653
594654impl < ' sess , S : Stage > AttributeParser < ' sess , S > {
595- pub fn new ( sess : & ' sess Session , features : & ' sess Features , tools : Vec < Symbol > ) -> Self {
596- Self { features : Some ( features) , tools, parse_only : None , sess, stage : PhantomData }
655+ pub fn new (
656+ sess : & ' sess Session ,
657+ features : & ' sess Features ,
658+ tools : Vec < Symbol > ,
659+ stage : S ,
660+ ) -> Self {
661+ Self { features : Some ( features) , tools, parse_only : None , sess, stage }
597662 }
598663
599664 pub ( crate ) fn sess ( & self ) -> & ' sess Session {
@@ -604,6 +669,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
604669 self . features . expect ( "features not available at this point in the compiler" )
605670 }
606671
672+ pub ( crate ) fn features_option ( & self ) -> Option < & ' sess Features > {
673+ self . features
674+ }
675+
607676 pub ( crate ) fn dcx ( & self ) -> DiagCtxtHandle < ' sess > {
608677 self . sess ( ) . dcx ( )
609678 }
0 commit comments