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