Skip to main content

rustc_parse/parser/
attr.rs

1use rustc_ast as ast;
2use rustc_ast::token::{self, MetaVarKind};
3use rustc_ast::tokenstream::ParserRange;
4use rustc_ast::{AttrItemKind, Attribute, attr};
5use rustc_errors::codes::*;
6use rustc_errors::{Diag, PResult, inline_fluent};
7use rustc_span::{BytePos, Span};
8use thin_vec::ThinVec;
9use tracing::debug;
10
11use super::{
12    AllowConstBlockItems, AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle,
13    Trailing, UsePreAttrPos,
14};
15use crate::parser::FnContext;
16use crate::{errors, exp};
17
18// Public for rustfmt usage
19#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InnerAttrPolicy {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            InnerAttrPolicy::Permitted =>
                ::core::fmt::Formatter::write_str(f, "Permitted"),
            InnerAttrPolicy::Forbidden(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Forbidden", &__self_0),
        }
    }
}Debug)]
20pub enum InnerAttrPolicy {
21    Permitted,
22    Forbidden(Option<InnerAttrForbiddenReason>),
23}
24
25#[derive(#[automatically_derived]
impl ::core::clone::Clone for InnerAttrForbiddenReason {
    #[inline]
    fn clone(&self) -> InnerAttrForbiddenReason {
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InnerAttrForbiddenReason { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for InnerAttrForbiddenReason {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            InnerAttrForbiddenReason::InCodeBlock =>
                ::core::fmt::Formatter::write_str(f, "InCodeBlock"),
            InnerAttrForbiddenReason::AfterOuterDocComment {
                prev_doc_comment_span: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "AfterOuterDocComment", "prev_doc_comment_span", &__self_0),
            InnerAttrForbiddenReason::AfterOuterAttribute {
                prev_outer_attr_sp: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "AfterOuterAttribute", "prev_outer_attr_sp", &__self_0),
        }
    }
}Debug)]
26pub enum InnerAttrForbiddenReason {
27    InCodeBlock,
28    AfterOuterDocComment { prev_doc_comment_span: Span },
29    AfterOuterAttribute { prev_outer_attr_sp: Span },
30}
31
32enum OuterAttributeType {
33    DocComment,
34    DocBlockComment,
35    Attribute,
36}
37
38#[derive(#[automatically_derived]
impl ::core::clone::Clone for AllowLeadingUnsafe {
    #[inline]
    fn clone(&self) -> AllowLeadingUnsafe { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AllowLeadingUnsafe { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for AllowLeadingUnsafe {
    #[inline]
    fn eq(&self, other: &AllowLeadingUnsafe) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for AllowLeadingUnsafe {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {}
}Eq)]
39pub enum AllowLeadingUnsafe {
40    Yes,
41    No,
42}
43
44impl<'a> Parser<'a> {
45    /// Parses attributes that appear before an item.
46    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
47        let mut outer_attrs = ast::AttrVec::new();
48        let mut just_parsed_doc_comment = false;
49        let start_pos = self.num_bump_calls;
50        loop {
51            let attr = if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Pound,
    token_type: crate::parser::token_type::TokenType::Pound,
}exp!(Pound)) {
52                let prev_outer_attr_sp = outer_attrs.last().map(|attr: &Attribute| attr.span);
53
54                let inner_error_reason = if just_parsed_doc_comment {
55                    Some(InnerAttrForbiddenReason::AfterOuterDocComment {
56                        prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
57                    })
58                } else {
59                    prev_outer_attr_sp.map(|prev_outer_attr_sp| {
60                        InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }
61                    })
62                };
63                let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
64                just_parsed_doc_comment = false;
65                Some(self.parse_attribute(inner_parse_policy)?)
66            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
67                if attr_style != ast::AttrStyle::Outer {
68                    let span = self.token.span;
69                    let mut err = self
70                        .dcx()
71                        .struct_span_err(span, rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected outer doc comment"))inline_fluent!("expected outer doc comment"));
72                    err.code(E0753);
73                    if let Some(replacement_span) = self.annotate_following_item_if_applicable(
74                        &mut err,
75                        span,
76                        match comment_kind {
77                            token::CommentKind::Line => OuterAttributeType::DocComment,
78                            token::CommentKind::Block => OuterAttributeType::DocBlockComment,
79                        },
80                        true,
81                    ) {
82                        err.note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("inner doc comments like this (starting with `//!` or `/*!`) can only appear before items"))inline_fluent!(
83                            "inner doc comments like this (starting with `//!` or `/*!`) can only appear before items"
84                        ));
85                        err.span_suggestion_verbose(
86                            replacement_span,
87                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("you might have meant to write a regular comment"))inline_fluent!("you might have meant to write a regular comment"),
88                            "",
89                            rustc_errors::Applicability::MachineApplicable,
90                        );
91                    }
92                    err.emit();
93                }
94                self.bump();
95                just_parsed_doc_comment = true;
96                // Always make an outer attribute - this allows us to recover from a misplaced
97                // inner attribute.
98                Some(attr::mk_doc_comment(
99                    &self.psess.attr_id_generator,
100                    comment_kind,
101                    ast::AttrStyle::Outer,
102                    data,
103                    self.prev_token.span,
104                ))
105            } else {
106                None
107            };
108
109            if let Some(attr) = attr {
110                if attr.style == ast::AttrStyle::Outer {
111                    outer_attrs.push(attr);
112                }
113            } else {
114                break;
115            }
116        }
117        Ok(AttrWrapper::new(outer_attrs, start_pos))
118    }
119
120    /// Matches `attribute = # ! [ meta_item ]`.
121    /// `inner_parse_policy` prescribes how to handle inner attributes.
122    // Public for rustfmt usage.
123    pub fn parse_attribute(
124        &mut self,
125        inner_parse_policy: InnerAttrPolicy,
126    ) -> PResult<'a, ast::Attribute> {
127        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/attr.rs:127",
                        "rustc_parse::parser::attr", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/attr.rs"),
                        ::tracing_core::__macro_support::Option::Some(127u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_parse::parser::attr"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("parse_attribute: inner_parse_policy={0:?} self.token={1:?}",
                                                    inner_parse_policy, self.token) as &dyn Value))])
            });
    } else { ; }
};debug!(
128            "parse_attribute: inner_parse_policy={:?} self.token={:?}",
129            inner_parse_policy, self.token
130        );
131        let lo = self.token.span;
132        // Attributes can't have attributes of their own [Editor's note: not with that attitude]
133        self.collect_tokens_no_attrs(|this| {
134            let pound_hi = this.token.span.hi();
135            if !this.eat(crate::parser::token_type::ExpTokenPair {
                tok: rustc_ast::token::Pound,
                token_type: crate::parser::token_type::TokenType::Pound,
            }) {
    {
        ::core::panicking::panic_fmt(format_args!("parse_attribute called in non-attribute position"));
    }
};assert!(this.eat(exp!(Pound)), "parse_attribute called in non-attribute position");
136
137            let not_lo = this.token.span.lo();
138            let style =
139                if this.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Bang,
    token_type: crate::parser::token_type::TokenType::Bang,
}exp!(Bang)) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
140
141            let mut bracket_res = this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenBracket,
    token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket));
142            // If `#!` is not followed by `[`
143            if let Err(err) = &mut bracket_res
144                && style == ast::AttrStyle::Inner
145                && pound_hi == not_lo
146            {
147                err.note(
148                    "the token sequence `#!` here looks like the start of \
149                    a shebang interpreter directive but it is not",
150                );
151                err.help(
152                    "if you meant this to be a shebang interpreter directive, \
153                    move it to the very start of the file",
154                );
155            }
156            bracket_res?;
157            let item = this.parse_attr_item(ForceCollect::No)?;
158            this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseBracket,
    token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket))?;
159            let attr_sp = lo.to(this.prev_token.span);
160
161            // Emit error if inner attribute is encountered and forbidden.
162            if style == ast::AttrStyle::Inner {
163                this.error_on_forbidden_inner_attr(
164                    attr_sp,
165                    inner_parse_policy,
166                    item.is_valid_for_outer_style(),
167                );
168            }
169
170            Ok(attr::mk_attr_from_item(&self.psess.attr_id_generator, item, None, style, attr_sp))
171        })
172    }
173
174    fn annotate_following_item_if_applicable(
175        &self,
176        err: &mut Diag<'_>,
177        span: Span,
178        attr_type: OuterAttributeType,
179        suggest_to_outer: bool,
180    ) -> Option<Span> {
181        let mut snapshot = self.create_snapshot_for_diagnostic();
182        let lo = span.lo()
183            + BytePos(match attr_type {
184                OuterAttributeType::Attribute => 1,
185                _ => 2,
186            });
187        let hi = lo + BytePos(1);
188        let replacement_span = span.with_lo(lo).with_hi(hi);
189        if let OuterAttributeType::DocBlockComment | OuterAttributeType::DocComment = attr_type {
190            snapshot.bump();
191        }
192        loop {
193            // skip any other attributes, we want the item
194            if snapshot.token == token::Pound {
195                if let Err(err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) {
196                    err.cancel();
197                    return Some(replacement_span);
198                }
199            } else {
200                break;
201            }
202        }
203        match snapshot.parse_item_common(
204            AttrWrapper::empty(),
205            true,
206            false,
207            FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true },
208            ForceCollect::No,
209            AllowConstBlockItems::Yes,
210        ) {
211            Ok(Some(item)) => {
212                err.arg("item", item.kind.descr());
213                err.span_label(
214                    item.span,
215                    match attr_type {
216                        OuterAttributeType::Attribute => {
217                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the inner attribute doesn't annotate this {$item}"))inline_fluent!("the inner attribute doesn't annotate this {$item}")
218                        }
219                        OuterAttributeType::DocComment | OuterAttributeType::DocBlockComment => {
220                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the inner doc comment doesn't annotate this {$item}"))inline_fluent!("the inner doc comment doesn't annotate this {$item}")
221                        }
222                    },
223                );
224                if suggest_to_outer {
225                    err.span_suggestion_verbose(
226                        replacement_span,
227                        match attr_type {
228                            OuterAttributeType::Attribute =>  rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("to annotate the {$item}, change the attribute from inner to outer style"))inline_fluent!("to annotate the {$item}, change the attribute from inner to outer style"),
229                            OuterAttributeType::DocComment | OuterAttributeType::DocBlockComment =>  rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("to annotate the {$item}, change the doc comment from inner to outer style"))inline_fluent!("to annotate the {$item}, change the doc comment from inner to outer style"),
230                        },
231                        match attr_type {
232                            OuterAttributeType::Attribute => "",
233                            OuterAttributeType::DocBlockComment => "*",
234                            OuterAttributeType::DocComment => "/",
235                        },
236                        rustc_errors::Applicability::MachineApplicable,
237                    );
238                }
239                return None;
240            }
241            Err(item_err) => {
242                item_err.cancel();
243            }
244            Ok(None) => {}
245        }
246        Some(replacement_span)
247    }
248
249    pub(super) fn error_on_forbidden_inner_attr(
250        &self,
251        attr_sp: Span,
252        policy: InnerAttrPolicy,
253        suggest_to_outer: bool,
254    ) {
255        if let InnerAttrPolicy::Forbidden(reason) = policy {
256            let mut diag = match reason.as_ref().copied() {
257                Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
258                    self.dcx()
259                        .struct_span_err(
260                            attr_sp,
261                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("an inner attribute is not permitted following an outer doc comment"))inline_fluent!(
262                                "an inner attribute is not permitted following an outer doc comment"
263                            ),
264                        )
265                        .with_span_label(
266                            attr_sp,
267                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("not permitted following an outer doc comment"))inline_fluent!("not permitted following an outer doc comment"),
268                        )
269                        .with_span_label(
270                            prev_doc_comment_span,
271                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("previous doc comment"))inline_fluent!("previous doc comment"),
272                        )
273                }
274                Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => self
275                    .dcx()
276                    .struct_span_err(
277                        attr_sp,
278                        rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("an inner attribute is not permitted following an outer attribute"))inline_fluent!(
279                            "an inner attribute is not permitted following an outer attribute"
280                        ),
281                    )
282                    .with_span_label(
283                        attr_sp,
284                        rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("not permitted following an outer attribute"))inline_fluent!("not permitted following an outer attribute"),
285                    )
286                    .with_span_label(
287                        prev_outer_attr_sp,
288                        rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("previous outer attribute"))inline_fluent!("previous outer attribute"),
289                    ),
290                Some(InnerAttrForbiddenReason::InCodeBlock) | None => self.dcx().struct_span_err(
291                    attr_sp,
292                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("an inner attribute is not permitted in this context"))inline_fluent!("an inner attribute is not permitted in this context"),
293                ),
294            };
295
296            diag.note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files"))inline_fluent!("inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files"));
297            if self
298                .annotate_following_item_if_applicable(
299                    &mut diag,
300                    attr_sp,
301                    OuterAttributeType::Attribute,
302                    suggest_to_outer,
303                )
304                .is_some()
305            {
306                diag.note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("outer attributes, like `#[test]`, annotate the item following them"))inline_fluent!(
307                    "outer attributes, like `#[test]`, annotate the item following them"
308                ));
309            };
310            diag.emit();
311        }
312    }
313
314    /// Parses an inner part of an attribute (the path and following tokens).
315    /// The tokens must be either a delimited token stream, or empty token stream,
316    /// or the "legacy" key-value form.
317    ///     PATH `(` TOKEN_STREAM `)`
318    ///     PATH `[` TOKEN_STREAM `]`
319    ///     PATH `{` TOKEN_STREAM `}`
320    ///     PATH
321    ///     PATH `=` UNSUFFIXED_LIT
322    /// The delimiters or `=` are still put into the resulting token stream.
323    pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> {
324        if let Some(item) = self.eat_metavar_seq_with_matcher(
325            |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
    MetaVarKind::Meta { .. } => true,
    _ => false,
}matches!(mv_kind, MetaVarKind::Meta { .. }),
326            |this| this.parse_attr_item(force_collect),
327        ) {
328            return Ok(item);
329        }
330
331        // Attr items don't have attributes.
332        self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| {
333            let is_unsafe = this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Unsafe,
    token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe));
334            let unsafety = if is_unsafe {
335                let unsafe_span = this.prev_token.span;
336                this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
337                ast::Safety::Unsafe(unsafe_span)
338            } else {
339                ast::Safety::Default
340            };
341
342            let path = this.parse_path(PathStyle::Mod)?;
343            let args = this.parse_attr_args()?;
344            if is_unsafe {
345                this.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
346            }
347            Ok((
348                ast::AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
349                Trailing::No,
350                UsePreAttrPos::No,
351            ))
352        })
353    }
354
355    /// Parses attributes that appear after the opening of an item. These should
356    /// be preceded by an exclamation mark, but we accept and warn about one
357    /// terminated by a semicolon.
358    ///
359    /// Matches `inner_attrs*`.
360    pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
361        let mut attrs = ast::AttrVec::new();
362        loop {
363            let start_pos = self.num_bump_calls;
364            // Only try to parse if it is an inner attribute (has `!`).
365            let attr = if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Pound,
    token_type: crate::parser::token_type::TokenType::Pound,
}exp!(Pound)) && self.look_ahead(1, |t| t == &token::Bang) {
366                Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
367            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
368                if attr_style == ast::AttrStyle::Inner {
369                    self.bump();
370                    Some(attr::mk_doc_comment(
371                        &self.psess.attr_id_generator,
372                        comment_kind,
373                        attr_style,
374                        data,
375                        self.prev_token.span,
376                    ))
377                } else {
378                    None
379                }
380            } else {
381                None
382            };
383            if let Some(attr) = attr {
384                // If we are currently capturing tokens (i.e. we are within a call to
385                // `Parser::collect_tokens`) record the token positions of this inner attribute,
386                // for possible later processing in a `LazyAttrTokenStream`.
387                if let Capturing::Yes = self.capture_state.capturing {
388                    let end_pos = self.num_bump_calls;
389                    let parser_range = ParserRange(start_pos..end_pos);
390                    self.capture_state.inner_attr_parser_ranges.insert(attr.id, parser_range);
391                }
392                attrs.push(attr);
393            } else {
394                break;
395            }
396        }
397        Ok(attrs)
398    }
399
400    // Note: must be unsuffixed.
401    pub(crate) fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'a, ast::MetaItemLit> {
402        let lit = self.parse_meta_item_lit()?;
403        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/attr.rs:403",
                        "rustc_parse::parser::attr", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/attr.rs"),
                        ::tracing_core::__macro_support::Option::Some(403u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_parse::parser::attr"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("checking if {0:?} is unsuffixed",
                                                    lit) as &dyn Value))])
            });
    } else { ; }
};debug!("checking if {:?} is unsuffixed", lit);
404
405        if !lit.kind.is_unsuffixed() {
406            self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
407        }
408
409        Ok(lit)
410    }
411
412    /// Matches `COMMASEP(meta_item_inner)`.
413    pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> {
414        // Presumably, the majority of the time there will only be one attr.
415        let mut nmis = ThinVec::with_capacity(1);
416        while self.token != token::Eof {
417            nmis.push(self.parse_meta_item_inner()?);
418            if !self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
419                break;
420            }
421        }
422        Ok(nmis)
423    }
424
425    /// Parse a meta item per RFC 1559.
426    ///
427    /// ```ebnf
428    /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
429    /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
430    /// ```
431    pub fn parse_meta_item(
432        &mut self,
433        unsafe_allowed: AllowLeadingUnsafe,
434    ) -> PResult<'a, ast::MetaItem> {
435        if let Some(MetaVarKind::Meta { has_meta_form }) = self.token.is_metavar_seq() {
436            return if has_meta_form {
437                let attr_item = self
438                    .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
439                        this.parse_attr_item(ForceCollect::No)
440                    })
441                    .unwrap();
442                Ok(attr_item.meta(attr_item.path.span).unwrap())
443            } else {
444                self.unexpected_any()
445            };
446        }
447
448        let lo = self.token.span;
449        let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes {
450            self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
    kw: rustc_span::symbol::kw::Unsafe,
    token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe))
451        } else {
452            false
453        };
454        let unsafety = if is_unsafe {
455            let unsafe_span = self.prev_token.span;
456            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
457
458            ast::Safety::Unsafe(unsafe_span)
459        } else {
460            ast::Safety::Default
461        };
462
463        let path = self.parse_path(PathStyle::Mod)?;
464        let kind = self.parse_meta_item_kind()?;
465        if is_unsafe {
466            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::CloseParen,
    token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
467        }
468        let span = lo.to(self.prev_token.span);
469
470        Ok(ast::MetaItem { unsafety, path, kind, span })
471    }
472
473    pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
474        Ok(if self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Eq,
    token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
475            ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
476        } else if self.check(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::OpenParen,
    token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
477            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
478            ast::MetaItemKind::List(list)
479        } else {
480            ast::MetaItemKind::Word
481        })
482    }
483
484    /// Parse an inner meta item per RFC 1559.
485    ///
486    /// ```ebnf
487    /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
488    /// ```
489    pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::MetaItemInner> {
490        match self.parse_unsuffixed_meta_item_lit() {
491            Ok(lit) => return Ok(ast::MetaItemInner::Lit(lit)),
492            Err(err) => err.cancel(), // we provide a better error below
493        }
494
495        match self.parse_meta_item(AllowLeadingUnsafe::No) {
496            Ok(mi) => return Ok(ast::MetaItemInner::MetaItem(mi)),
497            Err(err) => err.cancel(), // we provide a better error below
498        }
499
500        let mut err = errors::InvalidMetaItem {
501            span: self.token.span,
502            descr: super::token_descr(&self.token),
503            quote_ident_sugg: None,
504        };
505
506        // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
507        // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
508        // when macro metavariables are involved.
509        if self.prev_token == token::Eq
510            && let token::Ident(..) = self.token.kind
511        {
512            let before = self.token.span.shrink_to_lo();
513            while let token::Ident(..) = self.token.kind {
514                self.bump();
515            }
516            err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
517                before,
518                after: self.prev_token.span.shrink_to_hi(),
519            });
520        }
521
522        Err(self.dcx().create_err(err))
523    }
524}