1use std::borrow::Borrow;
12use std::fmt::{Debug, Display};
13#[cfg(debug_assertions)]
14use std::sync::atomic::{AtomicBool, Ordering};
15
16use rustc_ast::token::{self, Delimiter, MetaVarKind};
17use rustc_ast::tokenstream::TokenStream;
18use rustc_ast::{
19 AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
20};
21use rustc_ast_pretty::pprust;
22use rustc_attr_ir::AttrPath;
23use rustc_errors::{Applicability, Diag, PResult};
24use rustc_parse::exp;
25use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
26use rustc_session::diagnostics::create_lit_error;
27use rustc_session::parse::ParseSess;
28use rustc_span::{Ident, Span, Symbol, sym};
29use thin_vec::ThinVec;
30
31use crate::ShouldEmit;
32use crate::diagnostics::{
33 AdditionalCommaSuggestion, ExpectedComma, InvalidMetaItem, InvalidMetaItemQuoteIdentSugg,
34 InvalidMetaItemRemoveNegSugg, MetaBadDelim, MetaBadDelimSugg, SuffixedLiteralInAttribute,
35};
36
37#[derive(#[automatically_derived]
impl<P: ::core::clone::Clone + Borrow<Path>> ::core::clone::Clone for
PathParser<P> {
#[inline]
fn clone(&self) -> PathParser<P> {
PathParser(::core::clone::Clone::clone(&self.0))
}
}Clone, #[automatically_derived]
impl<P: ::core::fmt::Debug + Borrow<Path>> ::core::fmt::Debug for
PathParser<P> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PathParser",
&&self.0)
}
}Debug)]
38pub struct PathParser<P: Borrow<Path>>(pub P);
39
40pub type OwnedPathParser = PathParser<Path>;
41pub type RefPathParser<'p> = PathParser<&'p Path>;
42
43impl<P: Borrow<Path>> PathParser<P> {
44 pub fn get_attribute_path(&self) -> AttrPath {
45 AttrPath {
46 segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
47 span: self.span(),
48 }
49 }
50
51 pub fn segments(&self) -> impl Iterator<Item = &Ident> {
52 self.0.borrow().segments.iter().map(|seg| &seg.ident)
53 }
54
55 pub fn span(&self) -> Span {
56 self.0.borrow().span
57 }
58
59 pub fn len(&self) -> usize {
60 self.0.borrow().segments.len()
61 }
62
63 pub fn segments_is(&self, segments: &[Symbol]) -> bool {
64 self.segments().map(|segment| &segment.name).eq(segments)
65 }
66
67 pub fn word(&self) -> Option<Ident> {
68 (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap())
69 }
70
71 pub fn word_sym(&self) -> Option<Symbol> {
72 self.word().map(|ident| ident.name)
73 }
74
75 pub fn word_is(&self, sym: Symbol) -> bool {
79 self.word().is_some_and(|i| i.name == sym)
80 }
81
82 pub fn starts_with(&self, segments: &[Symbol]) -> bool {
87 segments.len() < self.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
88 }
89}
90
91impl<P: Borrow<Path>> Display for PathParser<P> {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.write_fmt(format_args!("{0}", pprust::path_to_string(self.0.borrow())))write!(f, "{}", pprust::path_to_string(self.0.borrow()))
94 }
95}
96
97#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ArgParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ArgParser::NoArgs =>
::core::fmt::Formatter::write_str(f, "NoArgs"),
ArgParser::List(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "List",
&__self_0),
ArgParser::NameValue(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"NameValue", &__self_0),
}
}
}Debug)]
104#[must_use]
105pub enum ArgParser {
106 NoArgs,
107 List(MetaItemListParser),
108 NameValue(NameValueParser),
109}
110
111impl ArgParser {
112 pub fn span(&self) -> Option<Span> {
113 match self {
114 Self::NoArgs => None,
115 Self::List(l) => Some(l.span),
116 Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())),
117 }
118 }
119
120 pub fn from_attr_args<'sess>(
121 value: &AttrArgs,
122 parts: &[Symbol],
123 psess: &'sess ParseSess,
124 should_emit: ShouldEmit,
125 allow_expr_metavar: AllowExprMetavar,
126 ) -> Option<Self> {
127 Some(match value {
128 AttrArgs::Empty => Self::NoArgs,
129 AttrArgs::Delimited(args) => {
130 if #[allow(non_exhaustive_omitted_patterns)] match parts {
[sym::rustc_dummy] | [sym::diagnostic, ..] => true,
_ => false,
}matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
134 match MetaItemListParser::new(
135 &args.tokens,
136 args.dspan.entire(),
137 psess,
138 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
139 allow_expr_metavar,
140 ) {
141 Ok(p) => return Some(ArgParser::List(p)),
142 Err(e) => {
143 e.cancel();
148 return Some(ArgParser::List(MetaItemListParser {
149 sub_parsers: ThinVec::new(),
150 span: args.dspan.entire(),
151 }));
152 }
153 }
154 }
155
156 if args.delim != Delimiter::Parenthesis {
157 should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
158 span: args.dspan.entire(),
159 sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
160 }));
161 return None;
162 }
163
164 Self::List(
165 MetaItemListParser::new(
166 &args.tokens,
167 args.dspan.entire(),
168 psess,
169 should_emit,
170 allow_expr_metavar,
171 )
172 .map_err(|e| should_emit.emit_err(e))
173 .ok()?,
174 )
175 }
176 AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
177 eq_span: *eq_span,
178 value: expr_to_lit(psess, expr, expr.span, should_emit)
179 .map_err(|e| should_emit.emit_err(e))
180 .ok()??,
181 value_span: expr.span,
182 }),
183 })
184 }
185
186 pub fn as_list(&self) -> Option<&MetaItemListParser> {
193 match self {
194 Self::List(l) => Some(l),
195 Self::NameValue(_) | Self::NoArgs => None,
196 }
197 }
198
199 pub fn as_name_value(&self) -> Option<&NameValueParser> {
209 match self {
210 Self::NameValue(n) => Some(n),
211 Self::List(_) | Self::NoArgs => None,
212 }
213 }
214
215 pub fn as_no_args(&self) -> Result<(), Span> {
219 match self {
220 Self::NoArgs => Ok(()),
221 Self::List(args) => Err(args.span),
222 Self::NameValue(args) => Err(args.args_span()),
223 }
224 }
225
226 pub fn ignore_args(&self) {
228 #[cfg(debug_assertions)]
229 if let ArgParser::List(list) = self {
230 for item in list.mixed() {
231 item.ignore_args();
232 }
233 }
234 }
235}
236
237#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MetaItemOrLitParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MetaItemOrLitParser::MetaItemParser(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MetaItemParser", &__self_0),
MetaItemOrLitParser::Lit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Lit",
&__self_0),
}
}
}Debug)]
242pub enum MetaItemOrLitParser {
243 MetaItemParser(MetaItemParser),
244 Lit(MetaItemLit),
245}
246
247impl MetaItemOrLitParser {
248 pub fn parse_single<'sess>(
249 parser: &mut Parser<'sess>,
250 should_emit: ShouldEmit,
251 allow_expr_metavar: AllowExprMetavar,
252 ) -> PResult<'sess, MetaItemOrLitParser> {
253 let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
254 this.parse_meta_item_inner()
255 }
256
257 pub fn span(&self) -> Span {
258 match self {
259 MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
260 generic_meta_item_parser.span()
261 }
262 MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
263 }
264 }
265
266 pub fn as_lit(&self) -> Option<&MetaItemLit> {
267 match self {
268 MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
269 MetaItemOrLitParser::MetaItemParser(_) => None,
270 }
271 }
272
273 pub fn meta_item(&self) -> Option<&MetaItemParser> {
274 match self {
275 MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
276 MetaItemOrLitParser::Lit(_) => None,
277 }
278 }
279
280 pub fn meta_item_no_args(&self) -> Option<&MetaItemParser> {
282 let meta_item = self.meta_item()?;
283 match meta_item.args().as_no_args() {
284 Ok(()) => Some(meta_item),
285 Err(_) => None,
286 }
287 }
288
289 pub fn ignore_args(&self) {
291 #[cfg(debug_assertions)]
292 match self {
293 MetaItemOrLitParser::MetaItemParser(meta_item) => {
294 meta_item.ignore_args();
295 }
296 MetaItemOrLitParser::Lit(_) => {}
297 }
298 }
299}
300
301#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MetaItemParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"MetaItemParser", "path", &self.path, "args", &self.args,
"args_checked", &&self.args_checked)
}
}Debug)]
319pub struct MetaItemParser {
320 path: OwnedPathParser,
321 args: ArgParser,
322
323 #[cfg(debug_assertions)]
326 args_checked: AtomicBool,
327}
328
329impl MetaItemParser {
330 pub fn ident(&self) -> Option<Ident> {
332 if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
333 }
334
335 pub fn span(&self) -> Span {
336 if let Some(other) = self.args.span() {
337 self.path.borrow().span().with_hi(other.hi())
338 } else {
339 self.path.borrow().span()
340 }
341 }
342
343 pub fn path(&self) -> &OwnedPathParser {
349 &self.path
350 }
351
352 pub fn args(&self) -> &ArgParser {
354 #[cfg(debug_assertions)]
355 self.args_checked.store(true, Ordering::Relaxed);
356 &self.args
357 }
358
359 pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> {
366 self.path().word_is(sym).then(|| self.args())
367 }
368
369 pub fn ignore_args(&self) {
371 self.args().ignore_args();
372 }
373
374 #[cfg(debug_assertions)]
375 pub fn are_args_checked(&self) -> bool {
376 self.args_checked.load(Ordering::Relaxed)
377 }
378}
379
380#[derive(#[automatically_derived]
impl ::core::clone::Clone for NameValueParser {
#[inline]
fn clone(&self) -> NameValueParser {
NameValueParser {
eq_span: ::core::clone::Clone::clone(&self.eq_span),
value: ::core::clone::Clone::clone(&self.value),
value_span: ::core::clone::Clone::clone(&self.value_span),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for NameValueParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"NameValueParser", "eq_span", &self.eq_span, "value", &self.value,
"value_span", &&self.value_span)
}
}Debug)]
381pub struct NameValueParser {
382 pub eq_span: Span,
383 value: MetaItemLit,
384 pub value_span: Span,
385}
386
387impl NameValueParser {
388 pub fn value_as_lit(&self) -> &MetaItemLit {
389 &self.value
390 }
391
392 pub fn value_as_str(&self) -> Option<Symbol> {
393 self.value_as_lit().kind.str()
394 }
395
396 pub fn value_as_ident(&self) -> Option<Ident> {
399 let meta_item = self.value_as_lit();
400 meta_item.kind.str().map(|name| Ident { name, span: meta_item.span })
401 }
402
403 pub fn args_span(&self) -> Span {
404 self.eq_span.to(self.value_span)
405 }
406}
407
408fn expr_to_lit<'sess>(
409 psess: &'sess ParseSess,
410 expr: &Expr,
411 span: Span,
412 should_emit: ShouldEmit,
413) -> PResult<'sess, Option<MetaItemLit>> {
414 if let ExprKind::Lit(token_lit) = expr.kind {
415 let res = MetaItemLit::from_token_lit(token_lit, expr.span);
416 match res {
417 Ok(lit) => {
418 if token_lit.suffix.is_some() {
419 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
420 } else if lit.kind.is_unsuffixed() {
421 Ok(Some(lit))
422 } else {
423 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
424 }
425 }
426 Err(err) => {
427 let err = create_lit_error(psess, err, token_lit, expr.span);
428 if #[allow(non_exhaustive_omitted_patterns)] match should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
429 should_emit,
430 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
431 ) {
432 Err(err)
433 } else {
434 let lit = MetaItemLit {
435 symbol: token_lit.symbol,
436 suffix: token_lit.suffix,
437 kind: LitKind::Err(err.emit()),
438 span: expr.span,
439 };
440 Ok(Some(lit))
441 }
442 }
443 }
444 } else {
445 if #[allow(non_exhaustive_omitted_patterns)] match should_emit {
ShouldEmit::Nothing => true,
_ => false,
}matches!(should_emit, ShouldEmit::Nothing) || #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Err(_) => true,
_ => false,
}matches!(expr.kind, ExprKind::Err(_)) {
446 return Ok(None);
447 }
448
449 let msg = "attribute value must be a literal";
454 let mut err = psess.dcx().struct_span_err(span, msg);
455
456 if let ExprKind::Path(None, ref path) = expr.kind
458 && let [_] = path.segments.as_slice()
459 {
460 err.multipart_suggestion(
461 "you might have meant to write a string literal",
462 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(expr.span.shrink_to_lo(), "\"".to_string()),
(expr.span.shrink_to_hi(), "\"".to_string())]))vec![
463 (expr.span.shrink_to_lo(), "\"".to_string()),
464 (expr.span.shrink_to_hi(), "\"".to_string()),
465 ],
466 Applicability::MaybeIncorrect,
467 );
468 }
469
470 Err(err)
471 }
472}
473
474#[derive(#[automatically_derived]
impl ::core::clone::Clone for AllowExprMetavar {
#[inline]
fn clone(&self) -> AllowExprMetavar { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AllowExprMetavar { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for AllowExprMetavar {
#[inline]
fn eq(&self, other: &AllowExprMetavar) -> 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 AllowExprMetavar {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
478pub enum AllowExprMetavar {
479 No,
480 Yes,
481}
482
483struct MetaItemListParserContext<'a, 'sess> {
484 parser: &'a mut Parser<'sess>,
485 should_emit: ShouldEmit,
486 allow_expr_metavar: AllowExprMetavar,
487}
488
489impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
490 fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
491 let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
492 self.unsuffixed_meta_item_from_lit(token_lit)
493 }
494
495 fn unsuffixed_meta_item_from_lit(
496 &mut self,
497 token_lit: token::Lit,
498 ) -> PResult<'sess, MetaItemLit> {
499 let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
500 Ok(lit) => lit,
501 Err(err) => {
502 return Err(create_lit_error(
503 self.parser.psess,
504 err,
505 token_lit,
506 self.parser.prev_token_uninterpolated_span(),
507 ));
508 }
509 };
510
511 if !lit.kind.is_unsuffixed() {
512 let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
514 if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
515 self.should_emit,
516 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
517 ) {
518 return Err(err);
519 }
520 self.should_emit.emit_err(err);
521 }
522
523 Ok(lit)
524 }
525
526 fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
527 if let Some(metavar) = self.parser.token.is_metavar_seq() {
528 match (metavar, self.allow_expr_metavar) {
529 (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
530 return self
531 .parser
532 .eat_metavar_seq(kind, |this| {
533 MetaItemListParserContext {
534 parser: this,
535 should_emit: self.should_emit,
536 allow_expr_metavar: AllowExprMetavar::Yes,
537 }
538 .parse_meta_item()
539 })
540 .ok_or_else(|| {
541 self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
542 });
543 }
544 (MetaVarKind::Meta { has_meta_form }, _) => {
545 return if has_meta_form {
546 let attr_item = self
547 .parser
548 .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
549 MetaItemListParserContext {
550 parser: this,
551 should_emit: self.should_emit,
552 allow_expr_metavar: self.allow_expr_metavar,
553 }
554 .parse_meta_item()
555 })
556 .unwrap();
557 Ok(attr_item)
558 } else {
559 self.parser.unexpected_any()
560 };
561 }
562 _ => {}
563 }
564 }
565
566 let path = self.parser.parse_path(PathStyle::Mod)?;
567
568 let args = if self.parser.check(::rustc_parse::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: ::rustc_parse::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
570 let start = self.parser.token.span;
571 let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
572 MetaItemListParserContext {
573 parser,
574 should_emit: self.should_emit,
575 allow_expr_metavar: self.allow_expr_metavar,
576 }
577 .parse_meta_item_inner()
578 })?;
579 let end = self.parser.prev_token.span;
580 ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
581 } else if self.parser.eat(::rustc_parse::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: ::rustc_parse::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
582 let eq_span = self.parser.prev_token.span;
583 let value = self.parse_unsuffixed_meta_item_lit()?;
584
585 ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
586 } else {
587 ArgParser::NoArgs
588 };
589
590 Ok(MetaItemParser {
591 path: PathParser(path),
592 args,
593 #[cfg(debug_assertions)]
594 args_checked: AtomicBool::new(false),
595 })
596 }
597
598 fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
599 if let Some(token_lit) = self.parser.eat_token_lit() {
600 Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
602 } else {
603 let prev_pros = self.parser.approx_token_stream_pos();
604 match self.parse_meta_item() {
605 Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
606 Err(err) => {
607 if self.parser.approx_token_stream_pos() == prev_pros {
610 err.cancel();
611 Err(self.expected_lit())
612 } else {
613 Err(err)
614 }
615 }
616 }
617 }
618 }
619
620 fn expected_lit(&mut self) -> Diag<'sess> {
621 let mut err = InvalidMetaItem {
622 span: self.parser.token.span,
623 descr: token_descr(&self.parser.token),
624 quote_ident_sugg: None,
625 remove_neg_sugg: None,
626 label: None,
627 };
628
629 if let token::OpenInvisible(_) = self.parser.token.kind {
630 return self.parser.dcx().create_err(err);
632 }
633
634 if let ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } = self.should_emit {
635 return self.parser.dcx().create_err(err);
639 }
640
641 let snapshot = self.parser.create_snapshot_for_diagnostic();
645 match self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false) {
646 Ok(stmt) => {
647 err.descr = stmt.kind.descr().to_string();
650 err.label = Some(stmt.span);
651 err.span = stmt.span;
652 if let StmtKind::Expr(expr) = &stmt.kind
653 && let ExprKind::Unary(UnOp::Neg, val) = &expr.kind
654 && let ExprKind::Lit(_) = val.kind
655 {
656 err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg {
657 negative_sign: expr.span.until(val.span),
658 });
659 } else if let StmtKind::Expr(expr) = &stmt.kind
660 && let ExprKind::Path(None, Path { segments, .. }) = &expr.kind
661 && segments.len() == 1
662 {
663 while let token::Ident(..) | token::Literal(_) | token::Dot =
664 self.parser.token.kind
665 {
666 self.parser.bump();
669 }
670 err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
671 before: expr.span.shrink_to_lo(),
672 after: self.parser.prev_token.span.shrink_to_hi(),
673 });
674 }
675 }
676 Err(e) => {
677 e.cancel();
678 self.parser.restore_snapshot(snapshot);
679 }
680 }
681
682 self.parser.dcx().create_err(err)
683 }
684
685 fn should_continue_parsing_meta_items(&mut self) -> Result<bool, Diag<'sess>> {
686 if self.parser.eat(::rustc_parse::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: ::rustc_parse::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
687 return Ok(true);
688 } else if self.parser.token == token::Eof {
689 return Ok(false);
690 }
691
692 let mut snapshot = self.parser.create_snapshot_for_diagnostic();
693 if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed } => true,
_ => false,
}matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }) {
694 let mut missing_commas = ThinVec::new();
695 let mut found_comma = false;
696 while self.parser.token != token::Eof {
697 let span = self.parser.prev_token.span.shrink_to_hi();
698 self.should_emit = ShouldEmit::Nothing;
699 match self.parse_meta_item_inner() {
700 Ok(_) => {
701 if !found_comma {
702 missing_commas.push(span);
703 }
704 }
705 Err(e) => {
706 e.cancel();
707 break;
708 }
709 }
710 found_comma = self.parser.eat(::rustc_parse::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: ::rustc_parse::parser::token_type::TokenType::Comma,
}exp!(Comma));
711 }
712
713 let mut missing_commas = missing_commas.into_iter();
714 if let Some(span) = missing_commas.next() {
715 let additional =
716 missing_commas.map(|span| AdditionalCommaSuggestion { span }).collect();
717 return Err(self.parser.dcx().create_err(ExpectedComma { span, additional }));
718 }
719 }
720 snapshot.unexpected_any()
721 }
722
723 fn parse(
724 tokens: TokenStream,
725 psess: &'sess ParseSess,
726 span: Span,
727 should_emit: ShouldEmit,
728 allow_expr_metavar: AllowExprMetavar,
729 ) -> PResult<'sess, MetaItemListParser> {
730 let mut parser = Parser::new(psess, tokens, None);
731 if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
732 parser = parser.recovery(recovery);
733 }
734
735 let mut this =
736 MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
737
738 let mut sub_parsers = ThinVec::with_capacity(1);
740 while this.parser.token != token::Eof {
741 sub_parsers.push(this.parse_meta_item_inner()?);
742
743 if !this.should_continue_parsing_meta_items()? {
744 break;
745 }
746 }
747
748 Ok(MetaItemListParser { sub_parsers, span })
749 }
750}
751
752#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MetaItemListParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"MetaItemListParser", "sub_parsers", &self.sub_parsers, "span",
&&self.span)
}
}Debug)]
753pub struct MetaItemListParser {
754 sub_parsers: ThinVec<MetaItemOrLitParser>,
755 pub span: Span,
756}
757
758impl MetaItemListParser {
759 pub(crate) fn new<'sess>(
760 tokens: &TokenStream,
761 span: Span,
762 psess: &'sess ParseSess,
763 should_emit: ShouldEmit,
764 allow_expr_metavar: AllowExprMetavar,
765 ) -> Result<Self, Diag<'sess>> {
766 MetaItemListParserContext::parse(
767 tokens.clone(),
768 psess,
769 span,
770 should_emit,
771 allow_expr_metavar,
772 )
773 }
774
775 pub fn mixed(&self) -> impl Iterator<Item = &MetaItemOrLitParser> {
777 self.sub_parsers.iter()
778 }
779
780 pub fn len(&self) -> usize {
781 self.sub_parsers.len()
782 }
783
784 pub fn is_empty(&self) -> bool {
785 self.len() == 0
786 }
787
788 pub fn as_single(&self) -> Option<&MetaItemOrLitParser> {
792 let mut iter = self.mixed();
793 iter.next().filter(|_| iter.next().is_none())
794 }
795}