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::{self as ast, LitKind, MetaItemLit, NodeId};
8use rustc_errors::{DiagCtxtHandle, Diagnostic};
9use rustc_feature::{AttributeTemplate, Features};
10use rustc_hir::attrs::AttributeKind;
11use rustc_hir::lints::{AttributeLint, AttributeLintKind};
12use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
13use rustc_session::Session;
14use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
15
16use crate::attributes::allow_unstable::{
17    AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
18};
19use crate::attributes::codegen_attrs::{
20    ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
21    OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
22    UsedParser,
23};
24use crate::attributes::confusables::ConfusablesParser;
25use crate::attributes::deprecation::DeprecationParser;
26use crate::attributes::dummy::DummyParser;
27use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
28use crate::attributes::link_attrs::{
29    ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
30    LinkSectionParser, StdInternalSymbolParser,
31};
32use crate::attributes::lint_helpers::{
33    AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
34};
35use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
36use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
37use crate::attributes::must_use::MustUseParser;
38use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
39use crate::attributes::non_exhaustive::NonExhaustiveParser;
40use crate::attributes::path::PathParser as PathAttributeParser;
41use crate::attributes::proc_macro_attrs::{
42    ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
43};
44use crate::attributes::repr::{AlignParser, ReprParser};
45use crate::attributes::rustc_internal::{
46    RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
47    RustcObjectLifetimeDefaultParser,
48};
49use crate::attributes::semantics::MayDangleParser;
50use crate::attributes::stability::{
51    BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
52};
53use crate::attributes::test_attrs::IgnoreParser;
54use crate::attributes::traits::{
55    AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
56    DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
57    ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser,
58    TypeConstParser, UnsafeSpecializationMarkerParser,
59};
60use crate::attributes::transparency::TransparencyParser;
61use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
62use crate::parser::{ArgParser, MetaItemParser, PathParser};
63use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
64
65macro_rules! group_type {
66    ($stage: ty) => {
67         LazyLock<(
68            BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
69            Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
70        )>
71    };
72}
73
74macro_rules! attribute_parsers {
75    (
76        pub(crate) static $name: ident = [$($names: ty),* $(,)?];
77    ) => {
78        mod early {
79            use super::*;
80            type Combine<T> = super::Combine<T, Early>;
81            type Single<T> = super::Single<T, Early>;
82            type WithoutArgs<T> = super::WithoutArgs<T, Early>;
83
84            attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
85        }
86        mod late {
87            use super::*;
88            type Combine<T> = super::Combine<T, Late>;
89            type Single<T> = super::Single<T, Late>;
90            type WithoutArgs<T> = super::WithoutArgs<T, Late>;
91
92            attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
93        }
94    };
95    (
96        @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
97    ) => {
98        pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
99            let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
100            let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
101            $(
102                {
103                    thread_local! {
104                        static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
105                    };
106
107                    for (path, template, accept_fn) in <$names>::ATTRIBUTES {
108                        accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
109                            STATE_OBJECT.with_borrow_mut(|s| {
110                                accept_fn(s, cx, args)
111                            })
112                        })));
113                    }
114
115                    finalizes.push(Box::new(|cx| {
116                        let state = STATE_OBJECT.take();
117                        state.finalize(cx)
118                    }));
119                }
120            )*
121
122            (accepts, finalizes)
123        });
124    };
125}
126attribute_parsers!(
127    pub(crate) static ATTRIBUTE_PARSERS = [
128        // tidy-alphabetical-start
129        AlignParser,
130        BodyStabilityParser,
131        ConfusablesParser,
132        ConstStabilityParser,
133        MacroUseParser,
134        NakedParser,
135        StabilityParser,
136        UsedParser,
137        // tidy-alphabetical-end
138
139        // tidy-alphabetical-start
140        Combine<AllowConstFnUnstableParser>,
141        Combine<AllowInternalUnstableParser>,
142        Combine<ReprParser>,
143        Combine<TargetFeatureParser>,
144        Combine<UnstableFeatureBoundParser>,
145        // tidy-alphabetical-end
146
147        // tidy-alphabetical-start
148        Single<CoverageParser>,
149        Single<DeprecationParser>,
150        Single<DummyParser>,
151        Single<ExportNameParser>,
152        Single<IgnoreParser>,
153        Single<InlineParser>,
154        Single<LinkNameParser>,
155        Single<LinkOrdinalParser>,
156        Single<LinkSectionParser>,
157        Single<MustUseParser>,
158        Single<OptimizeParser>,
159        Single<PathAttributeParser>,
160        Single<ProcMacroDeriveParser>,
161        Single<RustcBuiltinMacroParser>,
162        Single<RustcForceInlineParser>,
163        Single<RustcLayoutScalarValidRangeEnd>,
164        Single<RustcLayoutScalarValidRangeStart>,
165        Single<RustcObjectLifetimeDefaultParser>,
166        Single<SkipDuringMethodDispatchParser>,
167        Single<TransparencyParser>,
168        Single<WithoutArgs<AllowIncoherentImplParser>>,
169        Single<WithoutArgs<AsPtrParser>>,
170        Single<WithoutArgs<AutomaticallyDerivedParser>>,
171        Single<WithoutArgs<CoherenceIsCoreParser>>,
172        Single<WithoutArgs<CoinductiveParser>>,
173        Single<WithoutArgs<ColdParser>>,
174        Single<WithoutArgs<ConstContinueParser>>,
175        Single<WithoutArgs<ConstStabilityIndirectParser>>,
176        Single<WithoutArgs<ConstTraitParser>>,
177        Single<WithoutArgs<DenyExplicitImplParser>>,
178        Single<WithoutArgs<DoNotImplementViaObjectParser>>,
179        Single<WithoutArgs<ExportStableParser>>,
180        Single<WithoutArgs<FfiConstParser>>,
181        Single<WithoutArgs<FfiPureParser>>,
182        Single<WithoutArgs<FundamentalParser>>,
183        Single<WithoutArgs<LoopMatchParser>>,
184        Single<WithoutArgs<MacroEscapeParser>>,
185        Single<WithoutArgs<MarkerParser>>,
186        Single<WithoutArgs<MayDangleParser>>,
187        Single<WithoutArgs<NoImplicitPreludeParser>>,
188        Single<WithoutArgs<NoMangleParser>>,
189        Single<WithoutArgs<NonExhaustiveParser>>,
190        Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>,
191        Single<WithoutArgs<ParenSugarParser>>,
192        Single<WithoutArgs<PassByValueParser>>,
193        Single<WithoutArgs<PointeeParser>>,
194        Single<WithoutArgs<ProcMacroAttributeParser>>,
195        Single<WithoutArgs<ProcMacroParser>>,
196        Single<WithoutArgs<PubTransparentParser>>,
197        Single<WithoutArgs<SpecializationTraitParser>>,
198        Single<WithoutArgs<StdInternalSymbolParser>>,
199        Single<WithoutArgs<TrackCallerParser>>,
200        Single<WithoutArgs<TypeConstParser>>,
201        Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
202        // tidy-alphabetical-end
203    ];
204);
205
206mod private {
207    pub trait Sealed {}
208    impl Sealed for super::Early {}
209    impl Sealed for super::Late {}
210}
211
212// allow because it's a sealed trait
213#[allow(private_interfaces)]
214pub trait Stage: Sized + 'static + Sealed {
215    type Id: Copy;
216    const SHOULD_EMIT_LINTS: bool;
217
218    fn parsers() -> &'static group_type!(Self);
219
220    fn emit_err<'sess>(
221        &self,
222        sess: &'sess Session,
223        diag: impl for<'x> Diagnostic<'x>,
224    ) -> ErrorGuaranteed;
225}
226
227// allow because it's a sealed trait
228#[allow(private_interfaces)]
229impl Stage for Early {
230    type Id = NodeId;
231    const SHOULD_EMIT_LINTS: bool = false;
232
233    fn parsers() -> &'static group_type!(Self) {
234        &early::ATTRIBUTE_PARSERS
235    }
236    fn emit_err<'sess>(
237        &self,
238        sess: &'sess Session,
239        diag: impl for<'x> Diagnostic<'x>,
240    ) -> ErrorGuaranteed {
241        if self.emit_errors.should_emit() {
242            sess.dcx().emit_err(diag)
243        } else {
244            sess.dcx().create_err(diag).delay_as_bug()
245        }
246    }
247}
248
249// allow because it's a sealed trait
250#[allow(private_interfaces)]
251impl Stage for Late {
252    type Id = HirId;
253    const SHOULD_EMIT_LINTS: bool = true;
254
255    fn parsers() -> &'static group_type!(Self) {
256        &late::ATTRIBUTE_PARSERS
257    }
258    fn emit_err<'sess>(
259        &self,
260        tcx: &'sess Session,
261        diag: impl for<'x> Diagnostic<'x>,
262    ) -> ErrorGuaranteed {
263        tcx.dcx().emit_err(diag)
264    }
265}
266
267/// used when parsing attributes for miscellaneous things *before* ast lowering
268pub struct Early {
269    /// Whether to emit errors or delay them as a bug
270    /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
271    /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
272    pub emit_errors: ShouldEmit,
273}
274/// used when parsing attributes during ast lowering
275pub struct Late;
276
277/// Context given to every attribute parser when accepting
278///
279/// Gives [`AttributeParser`]s enough information to create errors, for example.
280pub struct AcceptContext<'f, 'sess, S: Stage> {
281    pub(crate) shared: SharedContext<'f, 'sess, S>,
282    /// The span of the attribute currently being parsed
283    pub(crate) attr_span: Span,
284
285    /// The expected structure of the attribute.
286    ///
287    /// Used in reporting errors to give a hint to users what the attribute *should* look like.
288    pub(crate) template: &'f AttributeTemplate,
289
290    /// The name of the attribute we're currently accepting.
291    pub(crate) attr_path: AttrPath,
292}
293
294impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
295    pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
296        self.stage.emit_err(&self.sess, diag)
297    }
298
299    /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
300    /// must be delayed until after HIR is built. This method will take care of the details of
301    /// that.
302    pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
303        if !S::SHOULD_EMIT_LINTS {
304            return;
305        }
306        let id = self.target_id;
307        (self.emit_lint)(AttributeLint { id, span, kind: lint });
308    }
309
310    pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
311        self.emit_lint(
312            AttributeLintKind::UnusedDuplicate {
313                this: unused_span,
314                other: used_span,
315                warning: false,
316            },
317            unused_span,
318        )
319    }
320
321    pub(crate) fn warn_unused_duplicate_future_error(
322        &mut self,
323        used_span: Span,
324        unused_span: Span,
325    ) {
326        self.emit_lint(
327            AttributeLintKind::UnusedDuplicate {
328                this: unused_span,
329                other: used_span,
330                warning: true,
331            },
332            unused_span,
333        )
334    }
335}
336
337impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
338    pub(crate) fn unknown_key(
339        &self,
340        span: Span,
341        found: String,
342        options: &'static [&'static str],
343    ) -> ErrorGuaranteed {
344        self.emit_err(UnknownMetaItem { span, item: found, expected: options })
345    }
346
347    /// error that a string literal was expected.
348    /// You can optionally give the literal you did find (which you found not to be a string literal)
349    /// which can make better errors. For example, if the literal was a byte string it will suggest
350    /// removing the `b` prefix.
351    pub(crate) fn expected_string_literal(
352        &self,
353        span: Span,
354        actual_literal: Option<&MetaItemLit>,
355    ) -> ErrorGuaranteed {
356        self.emit_err(AttributeParseError {
357            span,
358            attr_span: self.attr_span,
359            template: self.template.clone(),
360            attribute: self.attr_path.clone(),
361            reason: AttributeParseErrorReason::ExpectedStringLiteral {
362                byte_string: actual_literal.and_then(|i| {
363                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
364                }),
365            },
366        })
367    }
368
369    pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
370        self.emit_err(AttributeParseError {
371            span,
372            attr_span: self.attr_span,
373            template: self.template.clone(),
374            attribute: self.attr_path.clone(),
375            reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
376        })
377    }
378
379    pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
380        self.emit_err(AttributeParseError {
381            span,
382            attr_span: self.attr_span,
383            template: self.template.clone(),
384            attribute: self.attr_path.clone(),
385            reason: AttributeParseErrorReason::ExpectedList,
386        })
387    }
388
389    pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
390        self.emit_err(AttributeParseError {
391            span: args_span,
392            attr_span: self.attr_span,
393            template: self.template.clone(),
394            attribute: self.attr_path.clone(),
395            reason: AttributeParseErrorReason::ExpectedNoArgs,
396        })
397    }
398
399    /// emit an error that a `name` was expected here
400    pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
401        self.emit_err(AttributeParseError {
402            span,
403            attr_span: self.attr_span,
404            template: self.template.clone(),
405            attribute: self.attr_path.clone(),
406            reason: AttributeParseErrorReason::ExpectedIdentifier,
407        })
408    }
409
410    /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
411    /// a nicer error message talking about the specific name that was found lacking a value.
412    pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
413        self.emit_err(AttributeParseError {
414            span,
415            attr_span: self.attr_span,
416            template: self.template.clone(),
417            attribute: self.attr_path.clone(),
418            reason: AttributeParseErrorReason::ExpectedNameValue(name),
419        })
420    }
421
422    /// emit an error that a `name = value` pair was found where that name was already seen.
423    pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
424        self.emit_err(AttributeParseError {
425            span,
426            attr_span: self.attr_span,
427            template: self.template.clone(),
428            attribute: self.attr_path.clone(),
429            reason: AttributeParseErrorReason::DuplicateKey(key),
430        })
431    }
432
433    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
434    /// was expected *not* to be a literal, but instead a meta item.
435    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
436        self.emit_err(AttributeParseError {
437            span,
438            attr_span: self.attr_span,
439            template: self.template.clone(),
440            attribute: self.attr_path.clone(),
441            reason: AttributeParseErrorReason::UnexpectedLiteral,
442        })
443    }
444
445    pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
446        self.emit_err(AttributeParseError {
447            span,
448            attr_span: self.attr_span,
449            template: self.template.clone(),
450            attribute: self.attr_path.clone(),
451            reason: AttributeParseErrorReason::ExpectedSingleArgument,
452        })
453    }
454
455    pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
456        self.emit_err(AttributeParseError {
457            span,
458            attr_span: self.attr_span,
459            template: self.template.clone(),
460            attribute: self.attr_path.clone(),
461            reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
462        })
463    }
464
465    pub(crate) fn expected_specific_argument(
466        &self,
467        span: Span,
468        possibilities: Vec<&'static str>,
469    ) -> ErrorGuaranteed {
470        self.emit_err(AttributeParseError {
471            span,
472            attr_span: self.attr_span,
473            template: self.template.clone(),
474            attribute: self.attr_path.clone(),
475            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
476                possibilities,
477                strings: false,
478                list: false,
479            },
480        })
481    }
482
483    pub(crate) fn expected_specific_argument_and_list(
484        &self,
485        span: Span,
486        possibilities: Vec<&'static str>,
487    ) -> ErrorGuaranteed {
488        self.emit_err(AttributeParseError {
489            span,
490            attr_span: self.attr_span,
491            template: self.template.clone(),
492            attribute: self.attr_path.clone(),
493            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
494                possibilities,
495                strings: false,
496                list: true,
497            },
498        })
499    }
500
501    pub(crate) fn expected_specific_argument_strings(
502        &self,
503        span: Span,
504        possibilities: Vec<&'static str>,
505    ) -> ErrorGuaranteed {
506        self.emit_err(AttributeParseError {
507            span,
508            attr_span: self.attr_span,
509            template: self.template.clone(),
510            attribute: self.attr_path.clone(),
511            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
512                possibilities,
513                strings: true,
514                list: false,
515            },
516        })
517    }
518
519    pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
520        self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
521    }
522}
523
524impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
525    type Target = SharedContext<'f, 'sess, S>;
526
527    fn deref(&self) -> &Self::Target {
528        &self.shared
529    }
530}
531
532impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
533    fn deref_mut(&mut self) -> &mut Self::Target {
534        &mut self.shared
535    }
536}
537
538/// Context given to every attribute parser during finalization.
539///
540/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
541/// errors, for example.
542pub struct SharedContext<'p, 'sess, S: Stage> {
543    /// The parse context, gives access to the session and the
544    /// diagnostics context.
545    pub(crate) cx: &'p mut AttributeParser<'sess, S>,
546    /// The span of the syntactical component this attribute was applied to
547    pub(crate) target_span: Span,
548    /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
549    pub(crate) target_id: S::Id,
550
551    emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
552}
553
554/// Context given to every attribute parser during finalization.
555///
556/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
557/// errors, for example.
558pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
559    pub(crate) shared: SharedContext<'p, 'sess, S>,
560
561    /// A list of all attribute on this syntax node.
562    ///
563    /// Useful for compatibility checks with other attributes in [`finalize`](crate::attributes::AttributeParser::finalize)
564    ///
565    /// Usually, you should use normal attribute parsing logic instead,
566    /// especially when making a *denylist* of other attributes.
567    pub(crate) all_attrs: &'p [PathParser<'p>],
568}
569
570impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
571    type Target = SharedContext<'p, 'sess, S>;
572
573    fn deref(&self) -> &Self::Target {
574        &self.shared
575    }
576}
577
578impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
579    fn deref_mut(&mut self) -> &mut Self::Target {
580        &mut self.shared
581    }
582}
583
584impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> {
585    type Target = AttributeParser<'sess, S>;
586
587    fn deref(&self) -> &Self::Target {
588        self.cx
589    }
590}
591
592impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> {
593    fn deref_mut(&mut self) -> &mut Self::Target {
594        self.cx
595    }
596}
597
598#[derive(PartialEq, Clone, Copy, Debug)]
599pub enum OmitDoc {
600    Lower,
601    Skip,
602}
603
604#[derive(Copy, Clone)]
605pub enum ShouldEmit {
606    /// The operation will emit errors and lints.
607    /// This is usually what you need.
608    ErrorsAndLints,
609    /// The operation will emit *not* errors and lints.
610    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
611    Nothing,
612}
613
614impl ShouldEmit {
615    pub fn should_emit(&self) -> bool {
616        match self {
617            ShouldEmit::ErrorsAndLints => true,
618            ShouldEmit::Nothing => false,
619        }
620    }
621}
622
623/// Context created once, for example as part of the ast lowering
624/// context, through which all attributes can be lowered.
625pub struct AttributeParser<'sess, S: Stage = Late> {
626    pub(crate) tools: Vec<Symbol>,
627    features: Option<&'sess Features>,
628    sess: &'sess Session,
629    stage: S,
630
631    /// *Only* parse attributes with this symbol.
632    ///
633    /// Used in cases where we want the lowering infrastructure for parse just a single attribute.
634    parse_only: Option<Symbol>,
635}
636
637impl<'sess> AttributeParser<'sess, Early> {
638    /// This method allows you to parse attributes *before* you have access to features or tools.
639    /// One example where this is necessary, is to parse `feature` attributes themselves for
640    /// example.
641    ///
642    /// Try to use this as little as possible. Attributes *should* be lowered during
643    /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
644    /// crash if you tried to do so through [`parse_limited`](Self::parse_limited).
645    ///
646    /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
647    /// that symbol are picked out of the list of instructions and parsed. Those are returned.
648    ///
649    /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
650    /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
651    /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
652    pub fn parse_limited(
653        sess: &'sess Session,
654        attrs: &[ast::Attribute],
655        sym: Symbol,
656        target_span: Span,
657        target_node_id: NodeId,
658        features: Option<&'sess Features>,
659    ) -> Option<Attribute> {
660        let mut p = Self {
661            features,
662            tools: Vec::new(),
663            parse_only: Some(sym),
664            sess,
665            stage: Early { emit_errors: ShouldEmit::Nothing },
666        };
667        let mut parsed = p.parse_attribute_list(
668            attrs,
669            target_span,
670            target_node_id,
671            OmitDoc::Skip,
672            std::convert::identity,
673            |_lint| {
674                panic!("can't emit lints here for now (nothing uses this atm)");
675            },
676        );
677        assert!(parsed.len() <= 1);
678
679        parsed.pop()
680    }
681
682    pub fn parse_single<T>(
683        sess: &'sess Session,
684        attr: &ast::Attribute,
685        target_span: Span,
686        target_node_id: NodeId,
687        features: Option<&'sess Features>,
688        emit_errors: ShouldEmit,
689        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
690        template: &AttributeTemplate,
691    ) -> T {
692        let mut parser = Self {
693            features,
694            tools: Vec::new(),
695            parse_only: None,
696            sess,
697            stage: Early { emit_errors },
698        };
699        let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
700            panic!("parse_single called on a doc attr")
701        };
702        let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
703        let path = meta_parser.path();
704        let args = meta_parser.args();
705        let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
706            shared: SharedContext {
707                cx: &mut parser,
708                target_span,
709                target_id: target_node_id,
710                emit_lint: &mut |_lint| {
711                    panic!("can't emit lints here for now (nothing uses this atm)");
712                },
713            },
714            attr_span: attr.span,
715            template,
716            attr_path: path.get_attribute_path(),
717        };
718        parse_fn(&mut cx, args)
719    }
720}
721
722impl<'sess, S: Stage> AttributeParser<'sess, S> {
723    pub fn new(
724        sess: &'sess Session,
725        features: &'sess Features,
726        tools: Vec<Symbol>,
727        stage: S,
728    ) -> Self {
729        Self { features: Some(features), tools, parse_only: None, sess, stage }
730    }
731
732    pub(crate) fn sess(&self) -> &'sess Session {
733        &self.sess
734    }
735
736    pub(crate) fn features(&self) -> &'sess Features {
737        self.features.expect("features not available at this point in the compiler")
738    }
739
740    pub(crate) fn features_option(&self) -> Option<&'sess Features> {
741        self.features
742    }
743
744    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
745        self.sess().dcx()
746    }
747
748    /// Parse a list of attributes.
749    ///
750    /// `target_span` is the span of the thing this list of attributes is applied to,
751    /// and when `omit_doc` is set, doc attributes are filtered out.
752    pub fn parse_attribute_list(
753        &mut self,
754        attrs: &[ast::Attribute],
755        target_span: Span,
756        target_id: S::Id,
757        omit_doc: OmitDoc,
758
759        lower_span: impl Copy + Fn(Span) -> Span,
760        mut emit_lint: impl FnMut(AttributeLint<S::Id>),
761    ) -> Vec<Attribute> {
762        let mut attributes = Vec::new();
763        let mut attr_paths = Vec::new();
764
765        for attr in attrs {
766            // If we're only looking for a single attribute, skip all the ones we don't care about.
767            if let Some(expected) = self.parse_only {
768                if !attr.has_name(expected) {
769                    continue;
770                }
771            }
772
773            // Sometimes, for example for `#![doc = include_str!("readme.md")]`,
774            // doc still contains a non-literal. You might say, when we're lowering attributes
775            // that's expanded right? But no, sometimes, when parsing attributes on macros,
776            // we already use the lowering logic and these are still there. So, when `omit_doc`
777            // is set we *also* want to ignore these.
778            if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
779                continue;
780            }
781
782            match &attr.kind {
783                ast::AttrKind::DocComment(comment_kind, symbol) => {
784                    if omit_doc == OmitDoc::Skip {
785                        continue;
786                    }
787
788                    attributes.push(Attribute::Parsed(AttributeKind::DocComment {
789                        style: attr.style,
790                        kind: *comment_kind,
791                        span: lower_span(attr.span),
792                        comment: *symbol,
793                    }))
794                }
795                // // FIXME: make doc attributes go through a proper attribute parser
796                // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
797                //     let p = GenericMetaItemParser::from_attr(&n, self.dcx());
798                //
799                //     attributes.push(Attribute::Parsed(AttributeKind::DocComment {
800                //         style: attr.style,
801                //         kind: CommentKind::Line,
802                //         span: attr.span,
803                //         comment: p.args().name_value(),
804                //     }))
805                // }
806                ast::AttrKind::Normal(n) => {
807                    attr_paths.push(PathParser::Ast(&n.item.path));
808
809                    let parser = MetaItemParser::from_attr(n, self.dcx());
810                    let path = parser.path();
811                    let args = parser.args();
812                    let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
813
814                    if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
815                        for (template, accept) in accepts {
816                            let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
817                                shared: SharedContext {
818                                    cx: self,
819                                    target_span,
820                                    target_id,
821                                    emit_lint: &mut emit_lint,
822                                },
823                                attr_span: lower_span(attr.span),
824                                template,
825                                attr_path: path.get_attribute_path(),
826                            };
827
828                            accept(&mut cx, args)
829                        }
830                    } else {
831                        // If we're here, we must be compiling a tool attribute... Or someone
832                        // forgot to parse their fancy new attribute. Let's warn them in any case.
833                        // If you are that person, and you really think your attribute should
834                        // remain unparsed, carefully read the documentation in this module and if
835                        // you still think so you can add an exception to this assertion.
836
837                        // FIXME(jdonszelmann): convert other attributes, and check with this that
838                        // we caught em all
839                        // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg];
840                        // assert!(
841                        //     self.tools.contains(&parts[0]) || true,
842                        //     // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
843                        //     "attribute {path} wasn't parsed and isn't a know tool attribute",
844                        // );
845
846                        attributes.push(Attribute::Unparsed(Box::new(AttrItem {
847                            path: AttrPath::from_ast(&n.item.path),
848                            args: self.lower_attr_args(&n.item.args, lower_span),
849                            id: HashIgnoredAttrId { attr_id: attr.id },
850                            style: attr.style,
851                            span: lower_span(attr.span),
852                        })));
853                    }
854                }
855            }
856        }
857
858        let mut parsed_attributes = Vec::new();
859        for f in &S::parsers().1 {
860            if let Some(attr) = f(&mut FinalizeContext {
861                shared: SharedContext {
862                    cx: self,
863                    target_span,
864                    target_id,
865                    emit_lint: &mut emit_lint,
866                },
867                all_attrs: &attr_paths,
868            }) {
869                parsed_attributes.push(Attribute::Parsed(attr));
870            }
871        }
872
873        attributes.extend(parsed_attributes);
874
875        attributes
876    }
877
878    /// Returns whether there is a parser for an attribute with this name
879    pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
880        Late::parsers().0.contains_key(path)
881    }
882
883    fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
884        match args {
885            ast::AttrArgs::Empty => AttrArgs::Empty,
886            ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
887            // This is an inert key-value attribute - it will never be visible to macros
888            // after it gets lowered to HIR. Therefore, we can extract literals to handle
889            // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
890            ast::AttrArgs::Eq { eq_span, expr } => {
891                // In valid code the value always ends up as a single literal. Otherwise, a dummy
892                // literal suffices because the error is handled elsewhere.
893                let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
894                    && let Ok(lit) =
895                        ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
896                {
897                    lit
898                } else {
899                    let guar = self.dcx().span_delayed_bug(
900                        args.span().unwrap_or(DUMMY_SP),
901                        "expr in place where literal is expected (builtin attr parsing)",
902                    );
903                    ast::MetaItemLit {
904                        symbol: sym::dummy,
905                        suffix: None,
906                        kind: ast::LitKind::Err(guar),
907                        span: DUMMY_SP,
908                    }
909                };
910                AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
911            }
912        }
913    }
914}
915
916/// Parse a single integer.
917///
918/// Used by attributes that take a single integer as argument, such as
919/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
920/// `cx` is the context given to the attribute.
921/// `args` is the parser for the attribute arguments.
922pub(crate) fn parse_single_integer<S: Stage>(
923    cx: &mut AcceptContext<'_, '_, S>,
924    args: &ArgParser<'_>,
925) -> Option<u128> {
926    let Some(list) = args.list() else {
927        cx.expected_list(cx.attr_span);
928        return None;
929    };
930    let Some(single) = list.single() else {
931        cx.expected_single_argument(list.span);
932        return None;
933    };
934    let Some(lit) = single.lit() else {
935        cx.expected_integer_literal(single.span());
936        return None;
937    };
938    let LitKind::Int(num, _ty) = lit.kind else {
939        cx.expected_integer_literal(single.span());
940        return None;
941    };
942    Some(num.0)
943}