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