rustc_attr_parsing/
context.rs

1use std::cell::RefCell;
2use std::collections::BTreeMap;
3use std::ops::{Deref, DerefMut};
4use std::sync::LazyLock;
5
6use private::Sealed;
7use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
8use rustc_errors::{DiagCtxtHandle, Diagnostic};
9use rustc_feature::{AttributeTemplate, Features};
10use rustc_hir::attrs::AttributeKind;
11use rustc_hir::lints::{AttributeLint, AttributeLintKind};
12use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
13use rustc_session::Session;
14use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
15
16use crate::attributes::allow_unstable::{
17    AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
18};
19use crate::attributes::body::CoroutineParser;
20use crate::attributes::codegen_attrs::{
21    ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
22    TargetFeatureParser, TrackCallerParser, UsedParser,
23};
24use crate::attributes::confusables::ConfusablesParser;
25use crate::attributes::deprecation::DeprecationParser;
26use crate::attributes::dummy::DummyParser;
27use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
28use crate::attributes::link_attrs::{
29    ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
30    LinkSectionParser, LinkageParser, StdInternalSymbolParser,
31};
32use crate::attributes::lint_helpers::{
33    AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
34};
35use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
36use crate::attributes::macro_attrs::{
37    AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
38};
39use crate::attributes::must_use::MustUseParser;
40use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
41use crate::attributes::non_exhaustive::NonExhaustiveParser;
42use crate::attributes::path::PathParser as PathAttributeParser;
43use crate::attributes::proc_macro_attrs::{
44    ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
45};
46use crate::attributes::repr::{AlignParser, ReprParser};
47use crate::attributes::rustc_internal::{
48    RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
49    RustcObjectLifetimeDefaultParser,
50};
51use crate::attributes::semantics::MayDangleParser;
52use crate::attributes::stability::{
53    BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
54};
55use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
56use crate::attributes::traits::{
57    AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
58    DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
59    ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser,
60    TypeConstParser, UnsafeSpecializationMarkerParser,
61};
62use crate::attributes::transparency::TransparencyParser;
63use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
64use crate::parser::{ArgParser, MetaItemParser, PathParser};
65use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
66
67type GroupType<S> = LazyLock<GroupTypeInner<S>>;
68
69struct GroupTypeInner<S: Stage> {
70    accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
71    finalizers: Vec<FinalizeFn<S>>,
72}
73
74struct GroupTypeInnerAccept<S: Stage> {
75    template: AttributeTemplate,
76    accept_fn: AcceptFn<S>,
77}
78
79type AcceptFn<S> =
80    Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>;
81type FinalizeFn<S> =
82    Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
83
84macro_rules! attribute_parsers {
85    (
86        pub(crate) static $name: ident = [$($names: ty),* $(,)?];
87    ) => {
88        mod early {
89            use super::*;
90            type Combine<T> = super::Combine<T, Early>;
91            type Single<T> = super::Single<T, Early>;
92            type WithoutArgs<T> = super::WithoutArgs<T, Early>;
93
94            attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
95        }
96        mod late {
97            use super::*;
98            type Combine<T> = super::Combine<T, Late>;
99            type Single<T> = super::Single<T, Late>;
100            type WithoutArgs<T> = super::WithoutArgs<T, Late>;
101
102            attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
103        }
104    };
105    (
106        @[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
107    ) => {
108        pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
109            let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
110            let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
111            $(
112                {
113                    thread_local! {
114                        static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
115                    };
116
117                    for (path, template, accept_fn) in <$names>::ATTRIBUTES {
118                        accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
119                            template: *template,
120                            accept_fn: Box::new(|cx, args| {
121                                STATE_OBJECT.with_borrow_mut(|s| {
122                                    accept_fn(s, cx, args)
123                                })
124                            })
125                        });
126                    }
127
128                    finalizes.push(Box::new(|cx| {
129                        let state = STATE_OBJECT.take();
130                        state.finalize(cx)
131                    }));
132                }
133            )*
134
135            GroupTypeInner { accepters:accepts, finalizers:finalizes }
136        });
137    };
138}
139attribute_parsers!(
140    pub(crate) static ATTRIBUTE_PARSERS = [
141        // tidy-alphabetical-start
142        AlignParser,
143        BodyStabilityParser,
144        ConfusablesParser,
145        ConstStabilityParser,
146        MacroUseParser,
147        NakedParser,
148        StabilityParser,
149        UsedParser,
150        // tidy-alphabetical-end
151
152        // tidy-alphabetical-start
153        Combine<AllowConstFnUnstableParser>,
154        Combine<AllowInternalUnstableParser>,
155        Combine<ReprParser>,
156        Combine<TargetFeatureParser>,
157        Combine<UnstableFeatureBoundParser>,
158        // tidy-alphabetical-end
159
160        // tidy-alphabetical-start
161        Single<CoverageParser>,
162        Single<DeprecationParser>,
163        Single<DummyParser>,
164        Single<ExportNameParser>,
165        Single<IgnoreParser>,
166        Single<InlineParser>,
167        Single<LinkNameParser>,
168        Single<LinkOrdinalParser>,
169        Single<LinkSectionParser>,
170        Single<LinkageParser>,
171        Single<MustUseParser>,
172        Single<OptimizeParser>,
173        Single<PathAttributeParser>,
174        Single<ProcMacroDeriveParser>,
175        Single<RustcBuiltinMacroParser>,
176        Single<RustcForceInlineParser>,
177        Single<RustcLayoutScalarValidRangeEnd>,
178        Single<RustcLayoutScalarValidRangeStart>,
179        Single<RustcObjectLifetimeDefaultParser>,
180        Single<ShouldPanicParser>,
181        Single<SkipDuringMethodDispatchParser>,
182        Single<TransparencyParser>,
183        Single<WithoutArgs<AllowIncoherentImplParser>>,
184        Single<WithoutArgs<AllowInternalUnsafeParser>>,
185        Single<WithoutArgs<AsPtrParser>>,
186        Single<WithoutArgs<AutomaticallyDerivedParser>>,
187        Single<WithoutArgs<CoherenceIsCoreParser>>,
188        Single<WithoutArgs<CoinductiveParser>>,
189        Single<WithoutArgs<ColdParser>>,
190        Single<WithoutArgs<ConstContinueParser>>,
191        Single<WithoutArgs<ConstStabilityIndirectParser>>,
192        Single<WithoutArgs<ConstTraitParser>>,
193        Single<WithoutArgs<CoroutineParser>>,
194        Single<WithoutArgs<DenyExplicitImplParser>>,
195        Single<WithoutArgs<DoNotImplementViaObjectParser>>,
196        Single<WithoutArgs<ExportStableParser>>,
197        Single<WithoutArgs<FfiConstParser>>,
198        Single<WithoutArgs<FfiPureParser>>,
199        Single<WithoutArgs<FundamentalParser>>,
200        Single<WithoutArgs<LoopMatchParser>>,
201        Single<WithoutArgs<MacroEscapeParser>>,
202        Single<WithoutArgs<MarkerParser>>,
203        Single<WithoutArgs<MayDangleParser>>,
204        Single<WithoutArgs<NoImplicitPreludeParser>>,
205        Single<WithoutArgs<NoMangleParser>>,
206        Single<WithoutArgs<NonExhaustiveParser>>,
207        Single<WithoutArgs<ParenSugarParser>>,
208        Single<WithoutArgs<PassByValueParser>>,
209        Single<WithoutArgs<PointeeParser>>,
210        Single<WithoutArgs<ProcMacroAttributeParser>>,
211        Single<WithoutArgs<ProcMacroParser>>,
212        Single<WithoutArgs<PubTransparentParser>>,
213        Single<WithoutArgs<SpecializationTraitParser>>,
214        Single<WithoutArgs<StdInternalSymbolParser>>,
215        Single<WithoutArgs<TrackCallerParser>>,
216        Single<WithoutArgs<TypeConstParser>>,
217        Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
218        // tidy-alphabetical-end
219    ];
220);
221
222mod private {
223    pub trait Sealed {}
224    impl Sealed for super::Early {}
225    impl Sealed for super::Late {}
226}
227
228// allow because it's a sealed trait
229#[allow(private_interfaces)]
230pub trait Stage: Sized + 'static + Sealed {
231    type Id: Copy;
232
233    fn parsers() -> &'static GroupType<Self>;
234
235    fn emit_err<'sess>(
236        &self,
237        sess: &'sess Session,
238        diag: impl for<'x> Diagnostic<'x>,
239    ) -> ErrorGuaranteed;
240
241    fn should_emit(&self) -> ShouldEmit;
242}
243
244// allow because it's a sealed trait
245#[allow(private_interfaces)]
246impl Stage for Early {
247    type Id = NodeId;
248
249    fn parsers() -> &'static GroupType<Self> {
250        &early::ATTRIBUTE_PARSERS
251    }
252    fn emit_err<'sess>(
253        &self,
254        sess: &'sess Session,
255        diag: impl for<'x> Diagnostic<'x>,
256    ) -> ErrorGuaranteed {
257        if self.emit_errors.should_emit() {
258            sess.dcx().emit_err(diag)
259        } else {
260            sess.dcx().create_err(diag).delay_as_bug()
261        }
262    }
263
264    fn should_emit(&self) -> ShouldEmit {
265        self.emit_errors
266    }
267}
268
269// allow because it's a sealed trait
270#[allow(private_interfaces)]
271impl Stage for Late {
272    type Id = HirId;
273
274    fn parsers() -> &'static GroupType<Self> {
275        &late::ATTRIBUTE_PARSERS
276    }
277    fn emit_err<'sess>(
278        &self,
279        tcx: &'sess Session,
280        diag: impl for<'x> Diagnostic<'x>,
281    ) -> ErrorGuaranteed {
282        tcx.dcx().emit_err(diag)
283    }
284
285    fn should_emit(&self) -> ShouldEmit {
286        ShouldEmit::ErrorsAndLints
287    }
288}
289
290/// used when parsing attributes for miscellaneous things *before* ast lowering
291pub struct Early {
292    /// Whether to emit errors or delay them as a bug
293    /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
294    /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
295    pub emit_errors: ShouldEmit,
296}
297/// used when parsing attributes during ast lowering
298pub struct Late;
299
300/// Context given to every attribute parser when accepting
301///
302/// Gives [`AttributeParser`]s enough information to create errors, for example.
303pub struct AcceptContext<'f, 'sess, S: Stage> {
304    pub(crate) shared: SharedContext<'f, 'sess, S>,
305    /// The span of the attribute currently being parsed
306    pub(crate) attr_span: Span,
307
308    /// The expected structure of the attribute.
309    ///
310    /// Used in reporting errors to give a hint to users what the attribute *should* look like.
311    pub(crate) template: &'f AttributeTemplate,
312
313    /// The name of the attribute we're currently accepting.
314    pub(crate) attr_path: AttrPath,
315}
316
317impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
318    pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
319        self.stage.emit_err(&self.sess, diag)
320    }
321
322    /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
323    /// must be delayed until after HIR is built. This method will take care of the details of
324    /// that.
325    pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
326        if !self.stage.should_emit().should_emit() {
327            return;
328        }
329        let id = self.target_id;
330        (self.emit_lint)(AttributeLint { id, span, kind: lint });
331    }
332
333    pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
334        self.emit_lint(
335            AttributeLintKind::UnusedDuplicate {
336                this: unused_span,
337                other: used_span,
338                warning: false,
339            },
340            unused_span,
341        )
342    }
343
344    pub(crate) fn warn_unused_duplicate_future_error(
345        &mut self,
346        used_span: Span,
347        unused_span: Span,
348    ) {
349        self.emit_lint(
350            AttributeLintKind::UnusedDuplicate {
351                this: unused_span,
352                other: used_span,
353                warning: true,
354            },
355            unused_span,
356        )
357    }
358}
359
360impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
361    pub(crate) fn unknown_key(
362        &self,
363        span: Span,
364        found: String,
365        options: &'static [&'static str],
366    ) -> ErrorGuaranteed {
367        self.emit_err(UnknownMetaItem { span, item: found, expected: options })
368    }
369
370    /// error that a string literal was expected.
371    /// You can optionally give the literal you did find (which you found not to be a string literal)
372    /// which can make better errors. For example, if the literal was a byte string it will suggest
373    /// removing the `b` prefix.
374    pub(crate) fn expected_string_literal(
375        &self,
376        span: Span,
377        actual_literal: Option<&MetaItemLit>,
378    ) -> ErrorGuaranteed {
379        self.emit_err(AttributeParseError {
380            span,
381            attr_span: self.attr_span,
382            template: self.template.clone(),
383            attribute: self.attr_path.clone(),
384            reason: AttributeParseErrorReason::ExpectedStringLiteral {
385                byte_string: actual_literal.and_then(|i| {
386                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
387                }),
388            },
389        })
390    }
391
392    pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
393        self.emit_err(AttributeParseError {
394            span,
395            attr_span: self.attr_span,
396            template: self.template.clone(),
397            attribute: self.attr_path.clone(),
398            reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
399        })
400    }
401
402    pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
403        self.emit_err(AttributeParseError {
404            span,
405            attr_span: self.attr_span,
406            template: self.template.clone(),
407            attribute: self.attr_path.clone(),
408            reason: AttributeParseErrorReason::ExpectedList,
409        })
410    }
411
412    pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
413        self.emit_err(AttributeParseError {
414            span: args_span,
415            attr_span: self.attr_span,
416            template: self.template.clone(),
417            attribute: self.attr_path.clone(),
418            reason: AttributeParseErrorReason::ExpectedNoArgs,
419        })
420    }
421
422    /// emit an error that a `name` was expected here
423    pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
424        self.emit_err(AttributeParseError {
425            span,
426            attr_span: self.attr_span,
427            template: self.template.clone(),
428            attribute: self.attr_path.clone(),
429            reason: AttributeParseErrorReason::ExpectedIdentifier,
430        })
431    }
432
433    /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
434    /// a nicer error message talking about the specific name that was found lacking a value.
435    pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
436        self.emit_err(AttributeParseError {
437            span,
438            attr_span: self.attr_span,
439            template: self.template.clone(),
440            attribute: self.attr_path.clone(),
441            reason: AttributeParseErrorReason::ExpectedNameValue(name),
442        })
443    }
444
445    /// emit an error that a `name = value` pair was found where that name was already seen.
446    pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
447        self.emit_err(AttributeParseError {
448            span,
449            attr_span: self.attr_span,
450            template: self.template.clone(),
451            attribute: self.attr_path.clone(),
452            reason: AttributeParseErrorReason::DuplicateKey(key),
453        })
454    }
455
456    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
457    /// was expected *not* to be a literal, but instead a meta item.
458    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
459        self.emit_err(AttributeParseError {
460            span,
461            attr_span: self.attr_span,
462            template: self.template.clone(),
463            attribute: self.attr_path.clone(),
464            reason: AttributeParseErrorReason::UnexpectedLiteral,
465        })
466    }
467
468    pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
469        self.emit_err(AttributeParseError {
470            span,
471            attr_span: self.attr_span,
472            template: self.template.clone(),
473            attribute: self.attr_path.clone(),
474            reason: AttributeParseErrorReason::ExpectedSingleArgument,
475        })
476    }
477
478    pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
479        self.emit_err(AttributeParseError {
480            span,
481            attr_span: self.attr_span,
482            template: self.template.clone(),
483            attribute: self.attr_path.clone(),
484            reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
485        })
486    }
487
488    pub(crate) fn expected_specific_argument(
489        &self,
490        span: Span,
491        possibilities: Vec<&'static str>,
492    ) -> ErrorGuaranteed {
493        self.emit_err(AttributeParseError {
494            span,
495            attr_span: self.attr_span,
496            template: self.template.clone(),
497            attribute: self.attr_path.clone(),
498            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
499                possibilities,
500                strings: false,
501                list: false,
502            },
503        })
504    }
505
506    pub(crate) fn expected_specific_argument_and_list(
507        &self,
508        span: Span,
509        possibilities: Vec<&'static str>,
510    ) -> ErrorGuaranteed {
511        self.emit_err(AttributeParseError {
512            span,
513            attr_span: self.attr_span,
514            template: self.template.clone(),
515            attribute: self.attr_path.clone(),
516            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
517                possibilities,
518                strings: false,
519                list: true,
520            },
521        })
522    }
523
524    pub(crate) fn expected_specific_argument_strings(
525        &self,
526        span: Span,
527        possibilities: Vec<&'static str>,
528    ) -> ErrorGuaranteed {
529        self.emit_err(AttributeParseError {
530            span,
531            attr_span: self.attr_span,
532            template: self.template.clone(),
533            attribute: self.attr_path.clone(),
534            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
535                possibilities,
536                strings: true,
537                list: false,
538            },
539        })
540    }
541
542    pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
543        self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
544    }
545}
546
547impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
548    type Target = SharedContext<'f, 'sess, S>;
549
550    fn deref(&self) -> &Self::Target {
551        &self.shared
552    }
553}
554
555impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
556    fn deref_mut(&mut self) -> &mut Self::Target {
557        &mut self.shared
558    }
559}
560
561/// Context given to every attribute parser during finalization.
562///
563/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
564/// errors, for example.
565pub struct SharedContext<'p, 'sess, S: Stage> {
566    /// The parse context, gives access to the session and the
567    /// diagnostics context.
568    pub(crate) cx: &'p mut AttributeParser<'sess, S>,
569    /// The span of the syntactical component this attribute was applied to
570    pub(crate) target_span: Span,
571    /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
572    pub(crate) target_id: S::Id,
573
574    emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
575}
576
577/// Context given to every attribute parser during finalization.
578///
579/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
580/// errors, for example.
581pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
582    pub(crate) shared: SharedContext<'p, 'sess, S>,
583
584    /// A list of all attribute on this syntax node.
585    ///
586    /// Useful for compatibility checks with other attributes in [`finalize`](crate::attributes::AttributeParser::finalize)
587    ///
588    /// Usually, you should use normal attribute parsing logic instead,
589    /// especially when making a *denylist* of other attributes.
590    pub(crate) all_attrs: &'p [PathParser<'p>],
591}
592
593impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
594    type Target = SharedContext<'p, 'sess, S>;
595
596    fn deref(&self) -> &Self::Target {
597        &self.shared
598    }
599}
600
601impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
602    fn deref_mut(&mut self) -> &mut Self::Target {
603        &mut self.shared
604    }
605}
606
607impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> {
608    type Target = AttributeParser<'sess, S>;
609
610    fn deref(&self) -> &Self::Target {
611        self.cx
612    }
613}
614
615impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> {
616    fn deref_mut(&mut self) -> &mut Self::Target {
617        self.cx
618    }
619}
620
621#[derive(PartialEq, Clone, Copy, Debug)]
622pub enum OmitDoc {
623    Lower,
624    Skip,
625}
626
627#[derive(Copy, Clone)]
628pub enum ShouldEmit {
629    /// The operation will emit errors and lints.
630    /// This is usually what you need.
631    ErrorsAndLints,
632    /// The operation will emit *not* errors and lints.
633    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
634    Nothing,
635}
636
637impl ShouldEmit {
638    pub fn should_emit(&self) -> bool {
639        match self {
640            ShouldEmit::ErrorsAndLints => true,
641            ShouldEmit::Nothing => false,
642        }
643    }
644}
645
646/// Context created once, for example as part of the ast lowering
647/// context, through which all attributes can be lowered.
648pub struct AttributeParser<'sess, S: Stage = Late> {
649    pub(crate) tools: Vec<Symbol>,
650    features: Option<&'sess Features>,
651    sess: &'sess Session,
652    stage: S,
653
654    /// *Only* parse attributes with this symbol.
655    ///
656    /// Used in cases where we want the lowering infrastructure for parse just a single attribute.
657    parse_only: Option<Symbol>,
658}
659
660impl<'sess> AttributeParser<'sess, Early> {
661    /// This method allows you to parse attributes *before* you have access to features or tools.
662    /// One example where this is necessary, is to parse `feature` attributes themselves for
663    /// example.
664    ///
665    /// Try to use this as little as possible. Attributes *should* be lowered during
666    /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
667    /// crash if you tried to do so through [`parse_limited`](Self::parse_limited).
668    ///
669    /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
670    /// that symbol are picked out of the list of instructions and parsed. Those are returned.
671    ///
672    /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
673    /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
674    /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
675    pub fn parse_limited(
676        sess: &'sess Session,
677        attrs: &[ast::Attribute],
678        sym: Symbol,
679        target_span: Span,
680        target_node_id: NodeId,
681        features: Option<&'sess Features>,
682    ) -> Option<Attribute> {
683        let mut p = Self {
684            features,
685            tools: Vec::new(),
686            parse_only: Some(sym),
687            sess,
688            stage: Early { emit_errors: ShouldEmit::Nothing },
689        };
690        let mut parsed = p.parse_attribute_list(
691            attrs,
692            target_span,
693            target_node_id,
694            OmitDoc::Skip,
695            std::convert::identity,
696            |_lint| {
697                panic!("can't emit lints here for now (nothing uses this atm)");
698            },
699        );
700        assert!(parsed.len() <= 1);
701
702        parsed.pop()
703    }
704
705    pub fn parse_single<T>(
706        sess: &'sess Session,
707        attr: &ast::Attribute,
708        target_span: Span,
709        target_node_id: NodeId,
710        features: Option<&'sess Features>,
711        emit_errors: ShouldEmit,
712        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
713        template: &AttributeTemplate,
714    ) -> T {
715        let mut parser = Self {
716            features,
717            tools: Vec::new(),
718            parse_only: None,
719            sess,
720            stage: Early { emit_errors },
721        };
722        let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
723            panic!("parse_single called on a doc attr")
724        };
725        let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
726        let path = meta_parser.path();
727        let args = meta_parser.args();
728        let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
729            shared: SharedContext {
730                cx: &mut parser,
731                target_span,
732                target_id: target_node_id,
733                emit_lint: &mut |_lint| {
734                    panic!("can't emit lints here for now (nothing uses this atm)");
735                },
736            },
737            attr_span: attr.span,
738            template,
739            attr_path: path.get_attribute_path(),
740        };
741        parse_fn(&mut cx, args)
742    }
743}
744
745impl<'sess, S: Stage> AttributeParser<'sess, S> {
746    pub fn new(
747        sess: &'sess Session,
748        features: &'sess Features,
749        tools: Vec<Symbol>,
750        stage: S,
751    ) -> Self {
752        Self { features: Some(features), tools, parse_only: None, sess, stage }
753    }
754
755    pub(crate) fn sess(&self) -> &'sess Session {
756        &self.sess
757    }
758
759    pub(crate) fn features(&self) -> &'sess Features {
760        self.features.expect("features not available at this point in the compiler")
761    }
762
763    pub(crate) fn features_option(&self) -> Option<&'sess Features> {
764        self.features
765    }
766
767    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
768        self.sess().dcx()
769    }
770
771    /// Parse a list of attributes.
772    ///
773    /// `target_span` is the span of the thing this list of attributes is applied to,
774    /// and when `omit_doc` is set, doc attributes are filtered out.
775    pub fn parse_attribute_list(
776        &mut self,
777        attrs: &[ast::Attribute],
778        target_span: Span,
779        target_id: S::Id,
780        omit_doc: OmitDoc,
781
782        lower_span: impl Copy + Fn(Span) -> Span,
783        mut emit_lint: impl FnMut(AttributeLint<S::Id>),
784    ) -> Vec<Attribute> {
785        let mut attributes = Vec::new();
786        let mut attr_paths = Vec::new();
787
788        for attr in attrs {
789            // If we're only looking for a single attribute, skip all the ones we don't care about.
790            if let Some(expected) = self.parse_only {
791                if !attr.has_name(expected) {
792                    continue;
793                }
794            }
795
796            // Sometimes, for example for `#![doc = include_str!("readme.md")]`,
797            // doc still contains a non-literal. You might say, when we're lowering attributes
798            // that's expanded right? But no, sometimes, when parsing attributes on macros,
799            // we already use the lowering logic and these are still there. So, when `omit_doc`
800            // is set we *also* want to ignore these.
801            if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
802                continue;
803            }
804
805            match &attr.kind {
806                ast::AttrKind::DocComment(comment_kind, symbol) => {
807                    if omit_doc == OmitDoc::Skip {
808                        continue;
809                    }
810
811                    attributes.push(Attribute::Parsed(AttributeKind::DocComment {
812                        style: attr.style,
813                        kind: *comment_kind,
814                        span: lower_span(attr.span),
815                        comment: *symbol,
816                    }))
817                }
818                // // FIXME: make doc attributes go through a proper attribute parser
819                // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
820                //     let p = GenericMetaItemParser::from_attr(&n, self.dcx());
821                //
822                //     attributes.push(Attribute::Parsed(AttributeKind::DocComment {
823                //         style: attr.style,
824                //         kind: CommentKind::Line,
825                //         span: attr.span,
826                //         comment: p.args().name_value(),
827                //     }))
828                // }
829                ast::AttrKind::Normal(n) => {
830                    attr_paths.push(PathParser::Ast(&n.item.path));
831
832                    let parser = MetaItemParser::from_attr(n, self.dcx());
833                    let path = parser.path();
834                    let args = parser.args();
835                    let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
836
837                    if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
838                        for accept in accepts {
839                            let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
840                                shared: SharedContext {
841                                    cx: self,
842                                    target_span,
843                                    target_id,
844                                    emit_lint: &mut emit_lint,
845                                },
846                                attr_span: lower_span(attr.span),
847                                template: &accept.template,
848                                attr_path: path.get_attribute_path(),
849                            };
850
851                            (accept.accept_fn)(&mut cx, args)
852                        }
853                    } else {
854                        // If we're here, we must be compiling a tool attribute... Or someone
855                        // forgot to parse their fancy new attribute. Let's warn them in any case.
856                        // If you are that person, and you really think your attribute should
857                        // remain unparsed, carefully read the documentation in this module and if
858                        // you still think so you can add an exception to this assertion.
859
860                        // FIXME(jdonszelmann): convert other attributes, and check with this that
861                        // we caught em all
862                        // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg];
863                        // assert!(
864                        //     self.tools.contains(&parts[0]) || true,
865                        //     // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
866                        //     "attribute {path} wasn't parsed and isn't a know tool attribute",
867                        // );
868
869                        attributes.push(Attribute::Unparsed(Box::new(AttrItem {
870                            path: AttrPath::from_ast(&n.item.path),
871                            args: self.lower_attr_args(&n.item.args, lower_span),
872                            id: HashIgnoredAttrId { attr_id: attr.id },
873                            style: attr.style,
874                            span: lower_span(attr.span),
875                        })));
876                    }
877                }
878            }
879        }
880
881        let mut parsed_attributes = Vec::new();
882        for f in &S::parsers().finalizers {
883            if let Some(attr) = f(&mut FinalizeContext {
884                shared: SharedContext {
885                    cx: self,
886                    target_span,
887                    target_id,
888                    emit_lint: &mut emit_lint,
889                },
890                all_attrs: &attr_paths,
891            }) {
892                parsed_attributes.push(Attribute::Parsed(attr));
893            }
894        }
895
896        attributes.extend(parsed_attributes);
897
898        attributes
899    }
900
901    /// Returns whether there is a parser for an attribute with this name
902    pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
903        Late::parsers().accepters.contains_key(path)
904    }
905
906    fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
907        match args {
908            ast::AttrArgs::Empty => AttrArgs::Empty,
909            ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
910            // This is an inert key-value attribute - it will never be visible to macros
911            // after it gets lowered to HIR. Therefore, we can extract literals to handle
912            // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
913            ast::AttrArgs::Eq { eq_span, expr } => {
914                // In valid code the value always ends up as a single literal. Otherwise, a dummy
915                // literal suffices because the error is handled elsewhere.
916                let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
917                    && let Ok(lit) =
918                        ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
919                {
920                    lit
921                } else {
922                    let guar = self.dcx().span_delayed_bug(
923                        args.span().unwrap_or(DUMMY_SP),
924                        "expr in place where literal is expected (builtin attr parsing)",
925                    );
926                    ast::MetaItemLit {
927                        symbol: sym::dummy,
928                        suffix: None,
929                        kind: ast::LitKind::Err(guar),
930                        span: DUMMY_SP,
931                    }
932                };
933                AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
934            }
935        }
936    }
937}
938
939/// Parse a single integer.
940///
941/// Used by attributes that take a single integer as argument, such as
942/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
943/// `cx` is the context given to the attribute.
944/// `args` is the parser for the attribute arguments.
945pub(crate) fn parse_single_integer<S: Stage>(
946    cx: &mut AcceptContext<'_, '_, S>,
947    args: &ArgParser<'_>,
948) -> Option<u128> {
949    let Some(list) = args.list() else {
950        cx.expected_list(cx.attr_span);
951        return None;
952    };
953    let Some(single) = list.single() else {
954        cx.expected_single_argument(list.span);
955        return None;
956    };
957    let Some(lit) = single.lit() else {
958        cx.expected_integer_literal(single.span());
959        return None;
960    };
961    let LitKind::Int(num, _ty) = lit.kind else {
962        cx.expected_integer_literal(single.span());
963        return None;
964    };
965    Some(num.0)
966}