rustc_attr_parsing/
context.rs

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