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