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