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#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> {
414 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 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 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(), }
494
495 match self.parse_meta_item(AllowLeadingUnsafe::No) {
496 Ok(mi) => return Ok(ast::MetaItemInner::MetaItem(mi)),
497 Err(err) => err.cancel(), }
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 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}