rustc_attr_parsing/
context.rs

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