1use std::borrow::Borrow;
7use std::fmt::{Debug, Display};
8#[cfg(debug_assertions)]
9use std::sync::atomic::{AtomicBool, Ordering};
10
11use rustc_ast::token::{self, Delimiter, MetaVarKind};
12use rustc_ast::tokenstream::TokenStream;
13use rustc_ast::{
14 AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
15};
16use rustc_ast_pretty::pprust;
17use rustc_errors::{Applicability, Diag, PResult};
18use rustc_hir::{self as hir, AttrPath};
19use rustc_parse::exp;
20use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
21use rustc_session::errors::create_lit_error;
22use rustc_session::parse::ParseSess;
23use rustc_span::{Ident, Span, Symbol, sym};
24use thin_vec::ThinVec;
25
26use crate::ShouldEmit;
27use crate::session_diagnostics::{
28 InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim,
29 MetaBadDelimSugg, SuffixedLiteralInAttribute,
30};
31
32#[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)]
33pub struct PathParser<P: Borrow<Path>>(pub P);
34
35pub type OwnedPathParser = PathParser<Path>;
36pub type RefPathParser<'p> = PathParser<&'p Path>;
37
38impl<P: Borrow<Path>> PathParser<P> {
39 pub fn get_attribute_path(&self) -> hir::AttrPath {
40 AttrPath {
41 segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
42 span: self.span(),
43 }
44 }
45
46 pub fn segments(&self) -> impl Iterator<Item = &Ident> {
47 self.0.borrow().segments.iter().map(|seg| &seg.ident)
48 }
49
50 pub fn span(&self) -> Span {
51 self.0.borrow().span
52 }
53
54 pub fn len(&self) -> usize {
55 self.0.borrow().segments.len()
56 }
57
58 pub fn segments_is(&self, segments: &[Symbol]) -> bool {
59 self.segments().map(|segment| &segment.name).eq(segments)
60 }
61
62 pub fn word(&self) -> Option<Ident> {
63 (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap())
64 }
65
66 pub fn word_sym(&self) -> Option<Symbol> {
67 self.word().map(|ident| ident.name)
68 }
69
70 pub fn word_is(&self, sym: Symbol) -> bool {
74 self.word().map(|i| i.name == sym).unwrap_or(false)
75 }
76
77 pub fn starts_with(&self, segments: &[Symbol]) -> bool {
82 segments.len() < self.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
83 }
84}
85
86impl<P: Borrow<Path>> Display for PathParser<P> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 f.write_fmt(format_args!("{0}", pprust::path_to_string(self.0.borrow())))write!(f, "{}", pprust::path_to_string(self.0.borrow()))
89 }
90}
91
92#[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)]
93#[must_use]
94pub enum ArgParser {
95 NoArgs,
96 List(MetaItemListParser),
97 NameValue(NameValueParser),
98}
99
100impl ArgParser {
101 pub fn span(&self) -> Option<Span> {
102 match self {
103 Self::NoArgs => None,
104 Self::List(l) => Some(l.span),
105 Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())),
106 }
107 }
108
109 pub fn from_attr_args<'sess>(
110 value: &AttrArgs,
111 parts: &[Symbol],
112 psess: &'sess ParseSess,
113 should_emit: ShouldEmit,
114 allow_expr_metavar: AllowExprMetavar,
115 ) -> Option<Self> {
116 Some(match value {
117 AttrArgs::Empty => Self::NoArgs,
118 AttrArgs::Delimited(args) => {
119 if #[allow(non_exhaustive_omitted_patterns)] match parts {
[sym::rustc_dummy] | [sym::diagnostic, ..] => true,
_ => false,
}matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
123 match MetaItemListParser::new(
124 &args.tokens,
125 args.dspan.entire(),
126 psess,
127 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
128 allow_expr_metavar,
129 ) {
130 Ok(p) => return Some(ArgParser::List(p)),
131 Err(e) => {
132 e.cancel();
137 return Some(ArgParser::List(MetaItemListParser {
138 sub_parsers: ThinVec::new(),
139 span: args.dspan.entire(),
140 }));
141 }
142 }
143 }
144
145 if args.delim != Delimiter::Parenthesis {
146 should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
147 span: args.dspan.entire(),
148 sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
149 }));
150 return None;
151 }
152
153 Self::List(
154 MetaItemListParser::new(
155 &args.tokens,
156 args.dspan.entire(),
157 psess,
158 should_emit,
159 allow_expr_metavar,
160 )
161 .map_err(|e| should_emit.emit_err(e))
162 .ok()?,
163 )
164 }
165 AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
166 eq_span: *eq_span,
167 value: expr_to_lit(psess, &expr, expr.span, should_emit)
168 .map_err(|e| should_emit.emit_err(e))
169 .ok()??,
170 value_span: expr.span,
171 }),
172 })
173 }
174
175 pub fn as_list(&self) -> Option<&MetaItemListParser> {
182 match self {
183 Self::List(l) => Some(l),
184 Self::NameValue(_) | Self::NoArgs => None,
185 }
186 }
187
188 pub fn as_name_value(&self) -> Option<&NameValueParser> {
198 match self {
199 Self::NameValue(n) => Some(n),
200 Self::List(_) | Self::NoArgs => None,
201 }
202 }
203
204 pub fn as_no_args(&self) -> Result<(), Span> {
208 match self {
209 Self::NoArgs => Ok(()),
210 Self::List(args) => Err(args.span),
211 Self::NameValue(args) => Err(args.args_span()),
212 }
213 }
214
215 pub fn ignore_args(&self) {
217 #[cfg(debug_assertions)]
218 match self {
219 ArgParser::List(list) => {
220 for item in list.mixed() {
221 item.ignore_args();
222 }
223 }
224 _ => {}
225 }
226 }
227}
228
229#[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)]
234pub enum MetaItemOrLitParser {
235 MetaItemParser(MetaItemParser),
236 Lit(MetaItemLit),
237}
238
239impl MetaItemOrLitParser {
240 pub fn parse_single<'sess>(
241 parser: &mut Parser<'sess>,
242 should_emit: ShouldEmit,
243 allow_expr_metavar: AllowExprMetavar,
244 ) -> PResult<'sess, MetaItemOrLitParser> {
245 let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
246 this.parse_meta_item_inner()
247 }
248
249 pub fn span(&self) -> Span {
250 match self {
251 MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
252 generic_meta_item_parser.span()
253 }
254 MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
255 }
256 }
257
258 pub fn as_lit(&self) -> Option<&MetaItemLit> {
259 match self {
260 MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
261 MetaItemOrLitParser::MetaItemParser(_) => None,
262 }
263 }
264
265 pub fn meta_item(&self) -> Option<&MetaItemParser> {
266 match self {
267 MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
268 MetaItemOrLitParser::Lit(_) => None,
269 }
270 }
271
272 pub fn meta_item_no_args(&self) -> Option<&MetaItemParser> {
274 let meta_item = self.meta_item()?;
275 match meta_item.args().as_no_args() {
276 Ok(_) => Some(meta_item),
277 Err(_) => None,
278 }
279 }
280
281 pub fn ignore_args(&self) {
283 #[cfg(debug_assertions)]
284 match self {
285 MetaItemOrLitParser::MetaItemParser(meta_item) => {
286 meta_item.ignore_args();
287 }
288 MetaItemOrLitParser::Lit(_) => {}
289 }
290 }
291}
292
293pub struct MetaItemParser {
309 path: OwnedPathParser,
310 args: ArgParser,
311
312 #[cfg(debug_assertions)]
315 args_checked: AtomicBool,
316}
317
318impl Debug for MetaItemParser {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 f.debug_struct("MetaItemParser")
321 .field("path", &self.path)
322 .field("args", &self.args)
323 .finish()
324 }
325}
326
327impl MetaItemParser {
328 pub fn ident(&self) -> Option<Ident> {
330 if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
331 }
332
333 pub fn span(&self) -> Span {
334 if let Some(other) = self.args.span() {
335 self.path.borrow().span().with_hi(other.hi())
336 } else {
337 self.path.borrow().span()
338 }
339 }
340
341 pub fn path(&self) -> &OwnedPathParser {
347 &self.path
348 }
349
350 pub fn args(&self) -> &ArgParser {
352 #[cfg(debug_assertions)]
353 self.args_checked.store(true, Ordering::Relaxed);
354 &self.args
355 }
356
357 pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> {
364 self.path().word_is(sym).then(|| self.args())
365 }
366
367 pub fn ignore_args(&self) {
369 self.args().ignore_args();
370 }
371
372 #[cfg(debug_assertions)]
373 pub fn are_args_checked(&self) -> bool {
374 self.args_checked.load(Ordering::Relaxed)
375 }
376}
377
378#[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)]
379pub struct NameValueParser {
380 pub eq_span: Span,
381 value: MetaItemLit,
382 pub value_span: Span,
383}
384
385impl Debug for NameValueParser {
386 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387 f.debug_struct("NameValueParser")
388 .field("eq_span", &self.eq_span)
389 .field("value", &self.value)
390 .field("value_span", &self.value_span)
391 .finish()
392 }
393}
394
395impl NameValueParser {
396 pub fn value_as_lit(&self) -> &MetaItemLit {
397 &self.value
398 }
399
400 pub fn value_as_str(&self) -> Option<Symbol> {
401 self.value_as_lit().kind.str()
402 }
403
404 pub fn value_as_ident(&self) -> Option<Ident> {
407 let meta_item = self.value_as_lit();
408 meta_item.kind.str().map(|name| Ident { name, span: meta_item.span })
409 }
410
411 pub fn args_span(&self) -> Span {
412 self.eq_span.to(self.value_span)
413 }
414}
415
416fn expr_to_lit<'sess>(
417 psess: &'sess ParseSess,
418 expr: &Expr,
419 span: Span,
420 should_emit: ShouldEmit,
421) -> PResult<'sess, Option<MetaItemLit>> {
422 if let ExprKind::Lit(token_lit) = expr.kind {
423 let res = MetaItemLit::from_token_lit(token_lit, expr.span);
424 match res {
425 Ok(lit) => {
426 if token_lit.suffix.is_some() {
427 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
428 } else {
429 if lit.kind.is_unsuffixed() {
430 Ok(Some(lit))
431 } else {
432 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
433 }
434 }
435 }
436 Err(err) => {
437 let err = create_lit_error(psess, err, token_lit, expr.span);
438 if #[allow(non_exhaustive_omitted_patterns)] match should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
439 should_emit,
440 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
441 ) {
442 Err(err)
443 } else {
444 let lit = MetaItemLit {
445 symbol: token_lit.symbol,
446 suffix: token_lit.suffix,
447 kind: LitKind::Err(err.emit()),
448 span: expr.span,
449 };
450 Ok(Some(lit))
451 }
452 }
453 }
454 } else {
455 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(_)) {
456 return Ok(None);
457 }
458
459 let msg = "attribute value must be a literal";
464 let mut err = psess.dcx().struct_span_err(span, msg);
465
466 if let ExprKind::Path(None, ref path) = expr.kind
468 && let [segment] = path.segments.as_slice()
469 {
470 err.span_suggestion(
471 expr.span,
472 "try adding quotation marks",
473 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\"{0}\"", segment.ident))
})format!("\"{}\"", segment.ident),
474 Applicability::MaybeIncorrect,
475 );
476 }
477
478 Err(err)
479 }
480}
481
482#[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)]
486pub enum AllowExprMetavar {
487 No,
488 Yes,
489}
490
491struct MetaItemListParserContext<'a, 'sess> {
492 parser: &'a mut Parser<'sess>,
493 should_emit: ShouldEmit,
494 allow_expr_metavar: AllowExprMetavar,
495}
496
497impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
498 fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
499 let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
500 self.unsuffixed_meta_item_from_lit(token_lit)
501 }
502
503 fn unsuffixed_meta_item_from_lit(
504 &mut self,
505 token_lit: token::Lit,
506 ) -> PResult<'sess, MetaItemLit> {
507 let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
508 Ok(lit) => lit,
509 Err(err) => {
510 return Err(create_lit_error(
511 &self.parser.psess,
512 err,
513 token_lit,
514 self.parser.prev_token_uninterpolated_span(),
515 ));
516 }
517 };
518
519 if !lit.kind.is_unsuffixed() {
520 let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
522 if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
523 self.should_emit,
524 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
525 ) {
526 return Err(err);
527 } else {
528 self.should_emit.emit_err(err)
529 };
530 }
531
532 Ok(lit)
533 }
534
535 fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
536 if let Some(metavar) = self.parser.token.is_metavar_seq() {
537 match (metavar, self.allow_expr_metavar) {
538 (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
539 return self
540 .parser
541 .eat_metavar_seq(kind, |this| {
542 MetaItemListParserContext {
543 parser: this,
544 should_emit: self.should_emit,
545 allow_expr_metavar: AllowExprMetavar::Yes,
546 }
547 .parse_meta_item()
548 })
549 .ok_or_else(|| {
550 self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
551 });
552 }
553 (MetaVarKind::Meta { has_meta_form }, _) => {
554 return if has_meta_form {
555 let attr_item = self
556 .parser
557 .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
558 MetaItemListParserContext {
559 parser: this,
560 should_emit: self.should_emit,
561 allow_expr_metavar: self.allow_expr_metavar,
562 }
563 .parse_meta_item()
564 })
565 .unwrap();
566 Ok(attr_item)
567 } else {
568 self.parser.unexpected_any()
569 };
570 }
571 _ => {}
572 }
573 }
574
575 let path = self.parser.parse_path(PathStyle::Mod)?;
576
577 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)) {
579 let start = self.parser.token.span;
580 let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
581 MetaItemListParserContext {
582 parser,
583 should_emit: self.should_emit,
584 allow_expr_metavar: self.allow_expr_metavar,
585 }
586 .parse_meta_item_inner()
587 })?;
588 let end = self.parser.prev_token.span;
589 ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
590 } 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)) {
591 let eq_span = self.parser.prev_token.span;
592 let value = self.parse_unsuffixed_meta_item_lit()?;
593
594 ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
595 } else {
596 ArgParser::NoArgs
597 };
598
599 Ok(MetaItemParser {
600 path: PathParser(path),
601 args,
602 #[cfg(debug_assertions)]
603 args_checked: AtomicBool::new(false),
604 })
605 }
606
607 fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
608 if let Some(token_lit) = self.parser.eat_token_lit() {
609 Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
611 } else {
612 let prev_pros = self.parser.approx_token_stream_pos();
613 match self.parse_meta_item() {
614 Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
615 Err(err) => {
616 if self.parser.approx_token_stream_pos() != prev_pros {
619 Err(err)
620 } else {
621 err.cancel();
622 Err(self.expected_lit())
623 }
624 }
625 }
626 }
627 }
628
629 fn expected_lit(&mut self) -> Diag<'sess> {
630 let mut err = InvalidMetaItem {
631 span: self.parser.token.span,
632 descr: token_descr(&self.parser.token),
633 quote_ident_sugg: None,
634 remove_neg_sugg: None,
635 label: None,
636 };
637
638 if let token::OpenInvisible(_) = self.parser.token.kind {
639 return self.parser.dcx().create_err(err);
641 }
642
643 if let ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } = self.should_emit {
644 return self.parser.dcx().create_err(err);
648 }
649
650 let snapshot = self.parser.create_snapshot_for_diagnostic();
654 let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
655 match stmt {
656 Ok(Some(stmt)) => {
657 err.descr = stmt.kind.descr().to_string();
660 err.label = Some(stmt.span);
661 err.span = stmt.span;
662 if let StmtKind::Expr(expr) = &stmt.kind
663 && let ExprKind::Unary(UnOp::Neg, val) = &expr.kind
664 && let ExprKind::Lit(_) = val.kind
665 {
666 err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg {
667 negative_sign: expr.span.until(val.span),
668 });
669 } else if let StmtKind::Expr(expr) = &stmt.kind
670 && let ExprKind::Path(None, Path { segments, .. }) = &expr.kind
671 && segments.len() == 1
672 {
673 while let token::Ident(..) | token::Literal(_) | token::Dot =
674 self.parser.token.kind
675 {
676 self.parser.bump();
679 }
680 err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
681 before: expr.span.shrink_to_lo(),
682 after: self.parser.prev_token.span.shrink_to_hi(),
683 });
684 }
685 }
686 Ok(None) => {}
687 Err(e) => {
688 e.cancel();
689 self.parser.restore_snapshot(snapshot);
690 }
691 }
692
693 self.parser.dcx().create_err(err)
694 }
695
696 fn parse(
697 tokens: TokenStream,
698 psess: &'sess ParseSess,
699 span: Span,
700 should_emit: ShouldEmit,
701 allow_expr_metavar: AllowExprMetavar,
702 ) -> PResult<'sess, MetaItemListParser> {
703 let mut parser = Parser::new(psess, tokens, None);
704 if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
705 parser = parser.recovery(recovery);
706 }
707
708 let mut this =
709 MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
710
711 let mut sub_parsers = ThinVec::with_capacity(1);
713 while this.parser.token != token::Eof {
714 sub_parsers.push(this.parse_meta_item_inner()?);
715
716 if !this.parser.eat(::rustc_parse::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: ::rustc_parse::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
717 break;
718 }
719 }
720
721 if parser.token != token::Eof {
722 parser.unexpected()?;
723 }
724
725 Ok(MetaItemListParser { sub_parsers, span })
726 }
727}
728
729#[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)]
730pub struct MetaItemListParser {
731 sub_parsers: ThinVec<MetaItemOrLitParser>,
732 pub span: Span,
733}
734
735impl MetaItemListParser {
736 pub(crate) fn new<'sess>(
737 tokens: &TokenStream,
738 span: Span,
739 psess: &'sess ParseSess,
740 should_emit: ShouldEmit,
741 allow_expr_metavar: AllowExprMetavar,
742 ) -> Result<Self, Diag<'sess>> {
743 MetaItemListParserContext::parse(
744 tokens.clone(),
745 psess,
746 span,
747 should_emit,
748 allow_expr_metavar,
749 )
750 }
751
752 pub fn mixed(&self) -> impl Iterator<Item = &MetaItemOrLitParser> {
754 self.sub_parsers.iter()
755 }
756
757 pub fn len(&self) -> usize {
758 self.sub_parsers.len()
759 }
760
761 pub fn is_empty(&self) -> bool {
762 self.len() == 0
763 }
764
765 pub fn as_single(&self) -> Option<&MetaItemOrLitParser> {
769 let mut iter = self.mixed();
770 iter.next().filter(|_| iter.next().is_none())
771 }
772}