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