rustc_attr_parsing/
context.rs

1use std::cell::RefCell;
2use std::collections::BTreeMap;
3use std::ops::{Deref, DerefMut};
4use std::sync::LazyLock;
5
6use private::Sealed;
7use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
8use rustc_errors::{Diag, Diagnostic, Level};
9use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
10use rustc_hir::attrs::AttributeKind;
11use rustc_hir::lints::{AttributeLint, AttributeLintKind};
12use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
13use rustc_session::Session;
14use rustc_session::lint::{Lint, LintId};
15use rustc_span::{ErrorGuaranteed, Span, Symbol};
16
17use crate::AttributeParser;
18use crate::attributes::allow_unstable::{
19    AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
20};
21use crate::attributes::body::CoroutineParser;
22use crate::attributes::codegen_attrs::{
23    ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
24    NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
25    RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
26    TrackCallerParser, UsedParser,
27};
28use crate::attributes::confusables::ConfusablesParser;
29use crate::attributes::crate_level::{
30    CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
31    RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
32    WindowsSubsystemParser,
33};
34use crate::attributes::debugger::DebuggerViualizerParser;
35use crate::attributes::deprecation::DeprecationParser;
36use crate::attributes::dummy::DummyParser;
37use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
38use crate::attributes::link_attrs::{
39    ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
40    LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
41};
42use crate::attributes::lint_helpers::{
43    AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
44    RustcShouldNotBeCalledOnConstItems,
45};
46use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
47use crate::attributes::macro_attrs::{
48    AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
49};
50use crate::attributes::must_use::MustUseParser;
51use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
52use crate::attributes::non_exhaustive::NonExhaustiveParser;
53use crate::attributes::path::PathParser as PathAttributeParser;
54use crate::attributes::pin_v2::PinV2Parser;
55use crate::attributes::proc_macro_attrs::{
56    ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
57};
58use crate::attributes::prototype::CustomMirParser;
59use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
60use crate::attributes::rustc_internal::{
61    RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
62    RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
63};
64use crate::attributes::semantics::MayDangleParser;
65use crate::attributes::stability::{
66    BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
67};
68use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
69use crate::attributes::traits::{
70    AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
71    DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
72    PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
73    UnsafeSpecializationMarkerParser,
74};
75use crate::attributes::transparency::TransparencyParser;
76use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
77use crate::parser::{ArgParser, PathParser};
78use crate::session_diagnostics::{
79    AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem,
80};
81use crate::target_checking::AllowedTargets;
82
83type GroupType<S> = LazyLock<GroupTypeInner<S>>;
84
85pub(super) struct GroupTypeInner<S: Stage> {
86    pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
87    pub(super) finalizers: Vec<FinalizeFn<S>>,
88}
89
90pub(super) struct GroupTypeInnerAccept<S: Stage> {
91    pub(super) template: AttributeTemplate,
92    pub(super) accept_fn: AcceptFn<S>,
93    pub(super) allowed_targets: AllowedTargets,
94}
95
96type AcceptFn<S> =
97    Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>;
98type FinalizeFn<S> =
99    Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
100
101macro_rules! attribute_parsers {
102    (
103        pub(crate) static $name: ident = [$($names: ty),* $(,)?];
104    ) => {
105        mod early {
106            use super::*;
107            type Combine<T> = super::Combine<T, Early>;
108            type Single<T> = super::Single<T, Early>;
109            type WithoutArgs<T> = super::WithoutArgs<T, Early>;
110
111            attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
112        }
113        mod late {
114            use super::*;
115            type Combine<T> = super::Combine<T, Late>;
116            type Single<T> = super::Single<T, Late>;
117            type WithoutArgs<T> = super::WithoutArgs<T, Late>;
118
119            attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
120        }
121    };
122    (
123        @[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
124    ) => {
125        pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
126            let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
127            let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
128            $(
129                {
130                    thread_local! {
131                        static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
132                    };
133
134                    for (path, template, accept_fn) in <$names>::ATTRIBUTES {
135                        accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
136                            template: *template,
137                            accept_fn: Box::new(|cx, args| {
138                                STATE_OBJECT.with_borrow_mut(|s| {
139                                    accept_fn(s, cx, args)
140                                })
141                            }),
142                            allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
143                        });
144                    }
145
146                    finalizes.push(Box::new(|cx| {
147                        let state = STATE_OBJECT.take();
148                        state.finalize(cx)
149                    }));
150                }
151            )*
152
153            GroupTypeInner { accepters:accepts, finalizers:finalizes }
154        });
155    };
156}
157attribute_parsers!(
158    pub(crate) static ATTRIBUTE_PARSERS = [
159        // tidy-alphabetical-start
160        AlignParser,
161        AlignStaticParser,
162        BodyStabilityParser,
163        ConfusablesParser,
164        ConstStabilityParser,
165        MacroUseParser,
166        NakedParser,
167        StabilityParser,
168        UsedParser,
169        // tidy-alphabetical-end
170
171        // tidy-alphabetical-start
172        Combine<AllowConstFnUnstableParser>,
173        Combine<AllowInternalUnstableParser>,
174        Combine<DebuggerViualizerParser>,
175        Combine<ForceTargetFeatureParser>,
176        Combine<LinkParser>,
177        Combine<ReprParser>,
178        Combine<TargetFeatureParser>,
179        Combine<UnstableFeatureBoundParser>,
180        // tidy-alphabetical-end
181
182        // tidy-alphabetical-start
183        Single<CoverageParser>,
184        Single<CrateNameParser>,
185        Single<CustomMirParser>,
186        Single<DeprecationParser>,
187        Single<DummyParser>,
188        Single<ExportNameParser>,
189        Single<IgnoreParser>,
190        Single<InlineParser>,
191        Single<LinkNameParser>,
192        Single<LinkOrdinalParser>,
193        Single<LinkSectionParser>,
194        Single<LinkageParser>,
195        Single<MacroExportParser>,
196        Single<MoveSizeLimitParser>,
197        Single<MustUseParser>,
198        Single<ObjcClassParser>,
199        Single<ObjcSelectorParser>,
200        Single<OptimizeParser>,
201        Single<PathAttributeParser>,
202        Single<PatternComplexityLimitParser>,
203        Single<ProcMacroDeriveParser>,
204        Single<RecursionLimitParser>,
205        Single<RustcBuiltinMacroParser>,
206        Single<RustcForceInlineParser>,
207        Single<RustcLayoutScalarValidRangeEndParser>,
208        Single<RustcLayoutScalarValidRangeStartParser>,
209        Single<RustcObjectLifetimeDefaultParser>,
210        Single<RustcSimdMonomorphizeLaneLimitParser>,
211        Single<SanitizeParser>,
212        Single<ShouldPanicParser>,
213        Single<SkipDuringMethodDispatchParser>,
214        Single<TransparencyParser>,
215        Single<TypeLengthLimitParser>,
216        Single<WindowsSubsystemParser>,
217        Single<WithoutArgs<AllowIncoherentImplParser>>,
218        Single<WithoutArgs<AllowInternalUnsafeParser>>,
219        Single<WithoutArgs<AsPtrParser>>,
220        Single<WithoutArgs<AutomaticallyDerivedParser>>,
221        Single<WithoutArgs<CoinductiveParser>>,
222        Single<WithoutArgs<ColdParser>>,
223        Single<WithoutArgs<ConstContinueParser>>,
224        Single<WithoutArgs<ConstStabilityIndirectParser>>,
225        Single<WithoutArgs<CoroutineParser>>,
226        Single<WithoutArgs<DenyExplicitImplParser>>,
227        Single<WithoutArgs<DoNotImplementViaObjectParser>>,
228        Single<WithoutArgs<ExportStableParser>>,
229        Single<WithoutArgs<FfiConstParser>>,
230        Single<WithoutArgs<FfiPureParser>>,
231        Single<WithoutArgs<FundamentalParser>>,
232        Single<WithoutArgs<LoopMatchParser>>,
233        Single<WithoutArgs<MacroEscapeParser>>,
234        Single<WithoutArgs<MarkerParser>>,
235        Single<WithoutArgs<MayDangleParser>>,
236        Single<WithoutArgs<NoCoreParser>>,
237        Single<WithoutArgs<NoImplicitPreludeParser>>,
238        Single<WithoutArgs<NoMangleParser>>,
239        Single<WithoutArgs<NoStdParser>>,
240        Single<WithoutArgs<NonExhaustiveParser>>,
241        Single<WithoutArgs<ParenSugarParser>>,
242        Single<WithoutArgs<PassByValueParser>>,
243        Single<WithoutArgs<PinV2Parser>>,
244        Single<WithoutArgs<PointeeParser>>,
245        Single<WithoutArgs<ProcMacroAttributeParser>>,
246        Single<WithoutArgs<ProcMacroParser>>,
247        Single<WithoutArgs<PubTransparentParser>>,
248        Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
249        Single<WithoutArgs<RustcMainParser>>,
250        Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
251        Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
252        Single<WithoutArgs<SpecializationTraitParser>>,
253        Single<WithoutArgs<StdInternalSymbolParser>>,
254        Single<WithoutArgs<TrackCallerParser>>,
255        Single<WithoutArgs<TypeConstParser>>,
256        Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
257        // tidy-alphabetical-end
258    ];
259);
260
261mod private {
262    pub trait Sealed {}
263    impl Sealed for super::Early {}
264    impl Sealed for super::Late {}
265}
266
267// allow because it's a sealed trait
268#[allow(private_interfaces)]
269pub trait Stage: Sized + 'static + Sealed {
270    type Id: Copy;
271
272    fn parsers() -> &'static GroupType<Self>;
273
274    fn emit_err<'sess>(
275        &self,
276        sess: &'sess Session,
277        diag: impl for<'x> Diagnostic<'x>,
278    ) -> ErrorGuaranteed;
279
280    fn should_emit(&self) -> ShouldEmit;
281
282    fn id_is_crate_root(id: Self::Id) -> bool;
283}
284
285// allow because it's a sealed trait
286#[allow(private_interfaces)]
287impl Stage for Early {
288    type Id = NodeId;
289
290    fn parsers() -> &'static GroupType<Self> {
291        &early::ATTRIBUTE_PARSERS
292    }
293    fn emit_err<'sess>(
294        &self,
295        sess: &'sess Session,
296        diag: impl for<'x> Diagnostic<'x>,
297    ) -> ErrorGuaranteed {
298        self.should_emit().emit_err(sess.dcx().create_err(diag))
299    }
300
301    fn should_emit(&self) -> ShouldEmit {
302        self.emit_errors
303    }
304
305    fn id_is_crate_root(id: Self::Id) -> bool {
306        id == CRATE_NODE_ID
307    }
308}
309
310// allow because it's a sealed trait
311#[allow(private_interfaces)]
312impl Stage for Late {
313    type Id = HirId;
314
315    fn parsers() -> &'static GroupType<Self> {
316        &late::ATTRIBUTE_PARSERS
317    }
318    fn emit_err<'sess>(
319        &self,
320        tcx: &'sess Session,
321        diag: impl for<'x> Diagnostic<'x>,
322    ) -> ErrorGuaranteed {
323        tcx.dcx().emit_err(diag)
324    }
325
326    fn should_emit(&self) -> ShouldEmit {
327        ShouldEmit::ErrorsAndLints
328    }
329
330    fn id_is_crate_root(id: Self::Id) -> bool {
331        id == CRATE_HIR_ID
332    }
333}
334
335/// used when parsing attributes for miscellaneous things *before* ast lowering
336pub struct Early {
337    /// Whether to emit errors or delay them as a bug
338    /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
339    /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
340    pub emit_errors: ShouldEmit,
341}
342/// used when parsing attributes during ast lowering
343pub struct Late;
344
345/// Context given to every attribute parser when accepting
346///
347/// Gives [`AttributeParser`]s enough information to create errors, for example.
348pub struct AcceptContext<'f, 'sess, S: Stage> {
349    pub(crate) shared: SharedContext<'f, 'sess, S>,
350
351    /// The outer span of the attribute currently being parsed
352    /// #[attribute(...)]
353    /// ^^^^^^^^^^^^^^^^^ outer span
354    /// For attributes in `cfg_attr`, the outer span and inner spans are equal.
355    pub(crate) attr_span: Span,
356    /// The inner span of the attribute currently being parsed
357    /// #[attribute(...)]
358    ///   ^^^^^^^^^^^^^^  inner span
359    pub(crate) inner_span: Span,
360
361    /// Whether it is an inner or outer attribute
362    pub(crate) attr_style: AttrStyle,
363
364    /// A description of the thing we are parsing using this attribute parser
365    /// We are not only using these parsers for attributes, but also for macros such as the `cfg!()` macro.
366    pub(crate) parsed_description: ParsedDescription,
367
368    /// The expected structure of the attribute.
369    ///
370    /// Used in reporting errors to give a hint to users what the attribute *should* look like.
371    pub(crate) template: &'f AttributeTemplate,
372
373    /// The name of the attribute we're currently accepting.
374    pub(crate) attr_path: AttrPath,
375}
376
377impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
378    pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
379        self.stage.emit_err(&self.sess, diag)
380    }
381
382    /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
383    /// must be delayed until after HIR is built. This method will take care of the details of
384    /// that.
385    pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
386        if !matches!(
387            self.stage.should_emit(),
388            ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
389        ) {
390            return;
391        }
392        let id = self.target_id;
393        (self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind });
394    }
395
396    pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
397        self.emit_lint(
398            rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
399            AttributeLintKind::UnusedDuplicate {
400                this: unused_span,
401                other: used_span,
402                warning: false,
403            },
404            unused_span,
405        )
406    }
407
408    pub(crate) fn warn_unused_duplicate_future_error(
409        &mut self,
410        used_span: Span,
411        unused_span: Span,
412    ) {
413        self.emit_lint(
414            rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
415            AttributeLintKind::UnusedDuplicate {
416                this: unused_span,
417                other: used_span,
418                warning: true,
419            },
420            unused_span,
421        )
422    }
423}
424
425impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
426    pub(crate) fn unknown_key(
427        &self,
428        span: Span,
429        found: String,
430        options: &'static [&'static str],
431    ) -> ErrorGuaranteed {
432        self.emit_err(UnknownMetaItem { span, item: found, expected: options })
433    }
434
435    /// error that a string literal was expected.
436    /// You can optionally give the literal you did find (which you found not to be a string literal)
437    /// which can make better errors. For example, if the literal was a byte string it will suggest
438    /// removing the `b` prefix.
439    pub(crate) fn expected_string_literal(
440        &self,
441        span: Span,
442        actual_literal: Option<&MetaItemLit>,
443    ) -> ErrorGuaranteed {
444        self.emit_err(AttributeParseError {
445            span,
446            attr_span: self.attr_span,
447            template: self.template.clone(),
448            path: self.attr_path.clone(),
449            description: self.parsed_description,
450            reason: AttributeParseErrorReason::ExpectedStringLiteral {
451                byte_string: actual_literal.and_then(|i| {
452                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
453                }),
454            },
455            suggestions: self.suggestions(),
456        })
457    }
458
459    pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
460        self.emit_err(AttributeParseError {
461            span,
462            attr_span: self.attr_span,
463            template: self.template.clone(),
464            path: self.attr_path.clone(),
465            description: self.parsed_description,
466            reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
467            suggestions: self.suggestions(),
468        })
469    }
470
471    pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
472        self.emit_err(AttributeParseError {
473            span,
474            attr_span: self.attr_span,
475            template: self.template.clone(),
476            path: self.attr_path.clone(),
477            description: self.parsed_description,
478            reason: AttributeParseErrorReason::ExpectedList,
479            suggestions: self.suggestions(),
480        })
481    }
482
483    pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
484        self.emit_err(AttributeParseError {
485            span: args_span,
486            attr_span: self.attr_span,
487            template: self.template.clone(),
488            path: self.attr_path.clone(),
489            description: self.parsed_description,
490            reason: AttributeParseErrorReason::ExpectedNoArgs,
491            suggestions: self.suggestions(),
492        })
493    }
494
495    /// emit an error that a `name` was expected here
496    pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
497        self.emit_err(AttributeParseError {
498            span,
499            attr_span: self.attr_span,
500            template: self.template.clone(),
501            path: self.attr_path.clone(),
502            description: self.parsed_description,
503            reason: AttributeParseErrorReason::ExpectedIdentifier,
504            suggestions: self.suggestions(),
505        })
506    }
507
508    /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
509    /// a nicer error message talking about the specific name that was found lacking a value.
510    pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
511        self.emit_err(AttributeParseError {
512            span,
513            attr_span: self.attr_span,
514            template: self.template.clone(),
515            path: self.attr_path.clone(),
516            description: self.parsed_description,
517            reason: AttributeParseErrorReason::ExpectedNameValue(name),
518            suggestions: self.suggestions(),
519        })
520    }
521
522    /// emit an error that a `name = value` pair was found where that name was already seen.
523    pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
524        self.emit_err(AttributeParseError {
525            span,
526            attr_span: self.attr_span,
527            template: self.template.clone(),
528            path: self.attr_path.clone(),
529            description: self.parsed_description,
530            reason: AttributeParseErrorReason::DuplicateKey(key),
531            suggestions: self.suggestions(),
532        })
533    }
534
535    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
536    /// was expected *not* to be a literal, but instead a meta item.
537    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
538        self.emit_err(AttributeParseError {
539            span,
540            attr_span: self.attr_span,
541            template: self.template.clone(),
542            path: self.attr_path.clone(),
543            description: self.parsed_description,
544            reason: AttributeParseErrorReason::UnexpectedLiteral,
545            suggestions: self.suggestions(),
546        })
547    }
548
549    pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
550        self.emit_err(AttributeParseError {
551            span,
552            attr_span: self.attr_span,
553            template: self.template.clone(),
554            path: self.attr_path.clone(),
555            description: self.parsed_description,
556            reason: AttributeParseErrorReason::ExpectedSingleArgument,
557            suggestions: self.suggestions(),
558        })
559    }
560
561    pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
562        self.emit_err(AttributeParseError {
563            span,
564            attr_span: self.attr_span,
565            template: self.template.clone(),
566            path: self.attr_path.clone(),
567            description: self.parsed_description,
568            reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
569            suggestions: self.suggestions(),
570        })
571    }
572
573    /// produces an error along the lines of `expected one of [foo, meow]`
574    pub(crate) fn expected_specific_argument(
575        &self,
576        span: Span,
577        possibilities: &[Symbol],
578    ) -> ErrorGuaranteed {
579        self.emit_err(AttributeParseError {
580            span,
581            attr_span: self.attr_span,
582            template: self.template.clone(),
583            path: self.attr_path.clone(),
584            description: self.parsed_description,
585            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
586                possibilities,
587                strings: false,
588                list: false,
589            },
590            suggestions: self.suggestions(),
591        })
592    }
593
594    /// produces an error along the lines of `expected one of [foo, meow] as an argument`.
595    /// i.e. slightly different wording to [`expected_specific_argument`](Self::expected_specific_argument).
596    pub(crate) fn expected_specific_argument_and_list(
597        &self,
598        span: Span,
599        possibilities: &[Symbol],
600    ) -> ErrorGuaranteed {
601        self.emit_err(AttributeParseError {
602            span,
603            attr_span: self.attr_span,
604            template: self.template.clone(),
605            path: self.attr_path.clone(),
606            description: self.parsed_description,
607            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
608                possibilities,
609                strings: false,
610                list: true,
611            },
612            suggestions: self.suggestions(),
613        })
614    }
615
616    /// produces an error along the lines of `expected one of ["foo", "meow"]`
617    pub(crate) fn expected_specific_argument_strings(
618        &self,
619        span: Span,
620        possibilities: &[Symbol],
621    ) -> ErrorGuaranteed {
622        self.emit_err(AttributeParseError {
623            span,
624            attr_span: self.attr_span,
625            template: self.template.clone(),
626            path: self.attr_path.clone(),
627            description: self.parsed_description,
628            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
629                possibilities,
630                strings: true,
631                list: false,
632            },
633            suggestions: self.suggestions(),
634        })
635    }
636
637    pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
638        let attr_path = self.attr_path.clone().to_string();
639        let valid_without_list = self.template.word;
640        self.emit_lint(
641            rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
642            AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list },
643            span,
644        );
645    }
646
647    pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) {
648        let suggestions = self.suggestions();
649        let span = self.attr_span;
650        self.emit_lint(
651            lint,
652            AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
653            span,
654        );
655    }
656
657    pub(crate) fn suggestions(&self) -> Vec<String> {
658        let style = match self.parsed_description {
659            // If the outer and inner spans are equal, we are parsing an embedded attribute
660            ParsedDescription::Attribute if self.attr_span == self.inner_span => {
661                AttrSuggestionStyle::EmbeddedAttribute
662            }
663            ParsedDescription::Attribute => AttrSuggestionStyle::Attribute(self.attr_style),
664            ParsedDescription::Macro => AttrSuggestionStyle::Macro,
665        };
666
667        self.template.suggestions(style, &self.attr_path)
668    }
669}
670
671impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
672    type Target = SharedContext<'f, 'sess, S>;
673
674    fn deref(&self) -> &Self::Target {
675        &self.shared
676    }
677}
678
679impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
680    fn deref_mut(&mut self) -> &mut Self::Target {
681        &mut self.shared
682    }
683}
684
685/// Context given to every attribute parser during finalization.
686///
687/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
688/// errors, for example.
689pub struct SharedContext<'p, 'sess, S: Stage> {
690    /// The parse context, gives access to the session and the
691    /// diagnostics context.
692    pub(crate) cx: &'p mut AttributeParser<'sess, S>,
693    /// The span of the syntactical component this attribute was applied to
694    pub(crate) target_span: Span,
695    /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
696    pub(crate) target_id: S::Id,
697
698    pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
699}
700
701/// Context given to every attribute parser during finalization.
702///
703/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
704/// errors, for example.
705pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
706    pub(crate) shared: SharedContext<'p, 'sess, S>,
707
708    /// A list of all attribute on this syntax node.
709    ///
710    /// Useful for compatibility checks with other attributes in [`finalize`](crate::attributes::AttributeParser::finalize)
711    ///
712    /// Usually, you should use normal attribute parsing logic instead,
713    /// especially when making a *denylist* of other attributes.
714    pub(crate) all_attrs: &'p [PathParser<'p>],
715}
716
717impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
718    type Target = SharedContext<'p, 'sess, S>;
719
720    fn deref(&self) -> &Self::Target {
721        &self.shared
722    }
723}
724
725impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
726    fn deref_mut(&mut self) -> &mut Self::Target {
727        &mut self.shared
728    }
729}
730
731impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> {
732    type Target = AttributeParser<'sess, S>;
733
734    fn deref(&self) -> &Self::Target {
735        self.cx
736    }
737}
738
739impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> {
740    fn deref_mut(&mut self) -> &mut Self::Target {
741        self.cx
742    }
743}
744
745#[derive(PartialEq, Clone, Copy, Debug)]
746pub enum OmitDoc {
747    Lower,
748    Skip,
749}
750
751#[derive(Copy, Clone, Debug)]
752pub enum ShouldEmit {
753    /// The operations will emit errors, and lints, and errors are fatal.
754    ///
755    /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
756    /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
757    EarlyFatal { also_emit_lints: bool },
758    /// The operation will emit errors and lints.
759    /// This is usually what you need.
760    ErrorsAndLints,
761    /// The operation will emit *not* errors and lints.
762    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
763    Nothing,
764}
765
766impl ShouldEmit {
767    pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
768        match self {
769            ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
770            ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
771            ShouldEmit::ErrorsAndLints => diag.emit(),
772            ShouldEmit::Nothing => diag.delay_as_bug(),
773        }
774    }
775}