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