1use std::borrow::Borrow;
7use std::fmt::{Debug, Display};
8
9use rustc_ast::token::{self, Delimiter, MetaVarKind};
10use rustc_ast::tokenstream::TokenStream;
11use rustc_ast::{
12 AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
13};
14use rustc_ast_pretty::pprust;
15use rustc_errors::{Diag, PResult};
16use rustc_hir::{self as hir, AttrPath};
17use rustc_parse::exp;
18use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
19use rustc_session::errors::create_lit_error;
20use rustc_session::parse::ParseSess;
21use rustc_span::{Ident, Span, Symbol, sym};
22use thin_vec::ThinVec;
23
24use crate::ShouldEmit;
25use crate::session_diagnostics::{
26 InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim,
27 MetaBadDelimSugg, SuffixedLiteralInAttribute,
28};
29
30#[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)]
31pub struct PathParser<P: Borrow<Path>>(pub P);
32
33pub type OwnedPathParser = PathParser<Path>;
34pub type RefPathParser<'p> = PathParser<&'p Path>;
35
36impl<P: Borrow<Path>> PathParser<P> {
37 pub fn get_attribute_path(&self) -> hir::AttrPath {
38 AttrPath {
39 segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
40 span: self.span(),
41 }
42 }
43
44 pub fn segments(&self) -> impl Iterator<Item = &Ident> {
45 self.0.borrow().segments.iter().map(|seg| &seg.ident)
46 }
47
48 pub fn span(&self) -> Span {
49 self.0.borrow().span
50 }
51
52 pub fn len(&self) -> usize {
53 self.0.borrow().segments.len()
54 }
55
56 pub fn segments_is(&self, segments: &[Symbol]) -> bool {
57 self.segments().map(|segment| &segment.name).eq(segments)
58 }
59
60 pub fn word(&self) -> Option<Ident> {
61 (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap())
62 }
63
64 pub fn word_sym(&self) -> Option<Symbol> {
65 self.word().map(|ident| ident.name)
66 }
67
68 pub fn word_is(&self, sym: Symbol) -> bool {
72 self.word().map(|i| i.name == sym).unwrap_or(false)
73 }
74
75 pub fn starts_with(&self, segments: &[Symbol]) -> bool {
80 segments.len() < self.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
81 }
82}
83
84impl<P: Borrow<Path>> Display for PathParser<P> {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 f.write_fmt(format_args!("{0}", pprust::path_to_string(self.0.borrow())))write!(f, "{}", pprust::path_to_string(self.0.borrow()))
87 }
88}
89
90#[derive(#[automatically_derived]
impl ::core::clone::Clone for ArgParser {
#[inline]
fn clone(&self) -> ArgParser {
match self {
ArgParser::NoArgs => ArgParser::NoArgs,
ArgParser::List(__self_0) =>
ArgParser::List(::core::clone::Clone::clone(__self_0)),
ArgParser::NameValue(__self_0) =>
ArgParser::NameValue(::core::clone::Clone::clone(__self_0)),
}
}
}Clone, #[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)]
91#[must_use]
92pub enum ArgParser {
93 NoArgs,
94 List(MetaItemListParser),
95 NameValue(NameValueParser),
96}
97
98impl ArgParser {
99 pub fn span(&self) -> Option<Span> {
100 match self {
101 Self::NoArgs => None,
102 Self::List(l) => Some(l.span),
103 Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())),
104 }
105 }
106
107 pub fn from_attr_args<'sess>(
108 value: &AttrArgs,
109 parts: &[Symbol],
110 psess: &'sess ParseSess,
111 should_emit: ShouldEmit,
112 allow_expr_metavar: AllowExprMetavar,
113 ) -> Option<Self> {
114 Some(match value {
115 AttrArgs::Empty => Self::NoArgs,
116 AttrArgs::Delimited(args) => {
117 if #[allow(non_exhaustive_omitted_patterns)] match parts {
[sym::rustc_dummy] | [sym::diagnostic, ..] => true,
_ => false,
}matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
121 match MetaItemListParser::new(
122 &args.tokens,
123 args.dspan.entire(),
124 psess,
125 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
126 allow_expr_metavar,
127 ) {
128 Ok(p) => return Some(ArgParser::List(p)),
129 Err(e) => {
130 e.cancel();
135 return Some(ArgParser::List(MetaItemListParser {
136 sub_parsers: ThinVec::new(),
137 span: args.dspan.entire(),
138 }));
139 }
140 }
141 }
142
143 if args.delim != Delimiter::Parenthesis {
144 should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
145 span: args.dspan.entire(),
146 sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
147 }));
148 return None;
149 }
150
151 Self::List(
152 MetaItemListParser::new(
153 &args.tokens,
154 args.dspan.entire(),
155 psess,
156 should_emit,
157 allow_expr_metavar,
158 )
159 .map_err(|e| should_emit.emit_err(e))
160 .ok()?,
161 )
162 }
163 AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
164 eq_span: *eq_span,
165 value: expr_to_lit(psess, &expr, expr.span, should_emit)
166 .map_err(|e| should_emit.emit_err(e))
167 .ok()??,
168 value_span: expr.span,
169 }),
170 })
171 }
172
173 pub fn as_list(&self) -> Option<&MetaItemListParser> {
180 match self {
181 Self::List(l) => Some(l),
182 Self::NameValue(_) | Self::NoArgs => None,
183 }
184 }
185
186 pub fn as_name_value(&self) -> Option<&NameValueParser> {
196 match self {
197 Self::NameValue(n) => Some(n),
198 Self::List(_) | Self::NoArgs => None,
199 }
200 }
201
202 pub fn as_no_args(&self) -> Result<(), Span> {
206 match self {
207 Self::NoArgs => Ok(()),
208 Self::List(args) => Err(args.span),
209 Self::NameValue(args) => Err(args.args_span()),
210 }
211 }
212}
213
214#[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, #[automatically_derived]
impl ::core::clone::Clone for MetaItemOrLitParser {
#[inline]
fn clone(&self) -> MetaItemOrLitParser {
match self {
MetaItemOrLitParser::MetaItemParser(__self_0) =>
MetaItemOrLitParser::MetaItemParser(::core::clone::Clone::clone(__self_0)),
MetaItemOrLitParser::Lit(__self_0) =>
MetaItemOrLitParser::Lit(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
219pub enum MetaItemOrLitParser {
220 MetaItemParser(MetaItemParser),
221 Lit(MetaItemLit),
222}
223
224impl MetaItemOrLitParser {
225 pub fn parse_single<'sess>(
226 parser: &mut Parser<'sess>,
227 should_emit: ShouldEmit,
228 allow_expr_metavar: AllowExprMetavar,
229 ) -> PResult<'sess, MetaItemOrLitParser> {
230 let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
231 this.parse_meta_item_inner()
232 }
233
234 pub fn span(&self) -> Span {
235 match self {
236 MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
237 generic_meta_item_parser.span()
238 }
239 MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
240 }
241 }
242
243 pub fn lit(&self) -> Option<&MetaItemLit> {
244 match self {
245 MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
246 MetaItemOrLitParser::MetaItemParser(_) => None,
247 }
248 }
249
250 pub fn meta_item(&self) -> Option<&MetaItemParser> {
251 match self {
252 MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
253 MetaItemOrLitParser::Lit(_) => None,
254 }
255 }
256}
257
258#[derive(#[automatically_derived]
impl ::core::clone::Clone for MetaItemParser {
#[inline]
fn clone(&self) -> MetaItemParser {
MetaItemParser {
path: ::core::clone::Clone::clone(&self.path),
args: ::core::clone::Clone::clone(&self.args),
}
}
}Clone)]
274pub struct MetaItemParser {
275 path: OwnedPathParser,
276 args: ArgParser,
277}
278
279impl Debug for MetaItemParser {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 f.debug_struct("MetaItemParser")
282 .field("path", &self.path)
283 .field("args", &self.args)
284 .finish()
285 }
286}
287
288impl MetaItemParser {
289 pub fn ident(&self) -> Option<Ident> {
291 if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
292 }
293
294 pub fn span(&self) -> Span {
295 if let Some(other) = self.args.span() {
296 self.path.borrow().span().with_hi(other.hi())
297 } else {
298 self.path.borrow().span()
299 }
300 }
301
302 pub fn path(&self) -> &OwnedPathParser {
308 &self.path
309 }
310
311 pub fn args(&self) -> &ArgParser {
313 &self.args
314 }
315
316 pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> {
323 self.path().word_is(sym).then(|| self.args())
324 }
325}
326
327#[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)]
328pub struct NameValueParser {
329 pub eq_span: Span,
330 value: MetaItemLit,
331 pub value_span: Span,
332}
333
334impl Debug for NameValueParser {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 f.debug_struct("NameValueParser")
337 .field("eq_span", &self.eq_span)
338 .field("value", &self.value)
339 .field("value_span", &self.value_span)
340 .finish()
341 }
342}
343
344impl NameValueParser {
345 pub fn value_as_lit(&self) -> &MetaItemLit {
346 &self.value
347 }
348
349 pub fn value_as_str(&self) -> Option<Symbol> {
350 self.value_as_lit().kind.str()
351 }
352
353 pub fn value_as_ident(&self) -> Option<Ident> {
356 let meta_item = self.value_as_lit();
357 meta_item.kind.str().map(|name| Ident { name, span: meta_item.span })
358 }
359
360 pub fn args_span(&self) -> Span {
361 self.eq_span.to(self.value_span)
362 }
363}
364
365fn expr_to_lit<'sess>(
366 psess: &'sess ParseSess,
367 expr: &Expr,
368 span: Span,
369 should_emit: ShouldEmit,
370) -> PResult<'sess, Option<MetaItemLit>> {
371 if let ExprKind::Lit(token_lit) = expr.kind {
372 let res = MetaItemLit::from_token_lit(token_lit, expr.span);
373 match res {
374 Ok(lit) => {
375 if token_lit.suffix.is_some() {
376 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
377 } else {
378 if lit.kind.is_unsuffixed() {
379 Ok(Some(lit))
380 } else {
381 Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
382 }
383 }
384 }
385 Err(err) => {
386 let err = create_lit_error(psess, err, token_lit, expr.span);
387 if #[allow(non_exhaustive_omitted_patterns)] match should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
388 should_emit,
389 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
390 ) {
391 Err(err)
392 } else {
393 let lit = MetaItemLit {
394 symbol: token_lit.symbol,
395 suffix: token_lit.suffix,
396 kind: LitKind::Err(err.emit()),
397 span: expr.span,
398 };
399 Ok(Some(lit))
400 }
401 }
402 }
403 } else {
404 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(_)) {
405 return Ok(None);
406 }
407
408 let msg = "attribute value must be a literal";
413 let err = psess.dcx().struct_span_err(span, msg);
414 Err(err)
415 }
416}
417
418#[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)]
422pub enum AllowExprMetavar {
423 No,
424 Yes,
425}
426
427struct MetaItemListParserContext<'a, 'sess> {
428 parser: &'a mut Parser<'sess>,
429 should_emit: ShouldEmit,
430 allow_expr_metavar: AllowExprMetavar,
431}
432
433impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
434 fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
435 let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
436 self.unsuffixed_meta_item_from_lit(token_lit)
437 }
438
439 fn unsuffixed_meta_item_from_lit(
440 &mut self,
441 token_lit: token::Lit,
442 ) -> PResult<'sess, MetaItemLit> {
443 let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
444 Ok(lit) => lit,
445 Err(err) => {
446 return Err(create_lit_error(
447 &self.parser.psess,
448 err,
449 token_lit,
450 self.parser.prev_token_uninterpolated_span(),
451 ));
452 }
453 };
454
455 if !lit.kind.is_unsuffixed() {
456 let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
458 if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } => true,
_ => false,
}matches!(
459 self.should_emit,
460 ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
461 ) {
462 return Err(err);
463 } else {
464 self.should_emit.emit_err(err)
465 };
466 }
467
468 Ok(lit)
469 }
470
471 fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
472 if let Some(metavar) = self.parser.token.is_metavar_seq() {
473 match (metavar, self.allow_expr_metavar) {
474 (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
475 return self
476 .parser
477 .eat_metavar_seq(kind, |this| {
478 MetaItemListParserContext {
479 parser: this,
480 should_emit: self.should_emit,
481 allow_expr_metavar: AllowExprMetavar::Yes,
482 }
483 .parse_meta_item()
484 })
485 .ok_or_else(|| {
486 self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
487 });
488 }
489 (MetaVarKind::Meta { has_meta_form }, _) => {
490 return if has_meta_form {
491 let attr_item = self
492 .parser
493 .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
494 MetaItemListParserContext {
495 parser: this,
496 should_emit: self.should_emit,
497 allow_expr_metavar: self.allow_expr_metavar,
498 }
499 .parse_meta_item()
500 })
501 .unwrap();
502 Ok(attr_item)
503 } else {
504 self.parser.unexpected_any()
505 };
506 }
507 _ => {}
508 }
509 }
510
511 let path = self.parser.parse_path(PathStyle::Mod)?;
512
513 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)) {
515 let start = self.parser.token.span;
516 let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
517 MetaItemListParserContext {
518 parser,
519 should_emit: self.should_emit,
520 allow_expr_metavar: self.allow_expr_metavar,
521 }
522 .parse_meta_item_inner()
523 })?;
524 let end = self.parser.prev_token.span;
525 ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
526 } 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)) {
527 let eq_span = self.parser.prev_token.span;
528 let value = self.parse_unsuffixed_meta_item_lit()?;
529
530 ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
531 } else {
532 ArgParser::NoArgs
533 };
534
535 Ok(MetaItemParser { path: PathParser(path), args })
536 }
537
538 fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
539 if let Some(token_lit) = self.parser.eat_token_lit() {
540 Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
542 } else {
543 let prev_pros = self.parser.approx_token_stream_pos();
544 match self.parse_meta_item() {
545 Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
546 Err(err) => {
547 if self.parser.approx_token_stream_pos() != prev_pros {
550 Err(err)
551 } else {
552 err.cancel();
553 Err(self.expected_lit())
554 }
555 }
556 }
557 }
558 }
559
560 fn expected_lit(&mut self) -> Diag<'sess> {
561 let mut err = InvalidMetaItem {
562 span: self.parser.token.span,
563 descr: token_descr(&self.parser.token),
564 quote_ident_sugg: None,
565 remove_neg_sugg: None,
566 label: None,
567 };
568
569 if let token::OpenInvisible(_) = self.parser.token.kind {
570 return self.parser.dcx().create_err(err);
572 }
573
574 if let ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden } = self.should_emit {
575 return self.parser.dcx().create_err(err);
579 }
580
581 let snapshot = self.parser.create_snapshot_for_diagnostic();
585 let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
586 match stmt {
587 Ok(Some(stmt)) => {
588 err.descr = stmt.kind.descr().to_string();
591 err.label = Some(stmt.span);
592 err.span = stmt.span;
593 if let StmtKind::Expr(expr) = &stmt.kind
594 && let ExprKind::Unary(UnOp::Neg, val) = &expr.kind
595 && let ExprKind::Lit(_) = val.kind
596 {
597 err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg {
598 negative_sign: expr.span.until(val.span),
599 });
600 } else if let StmtKind::Expr(expr) = &stmt.kind
601 && let ExprKind::Path(None, Path { segments, .. }) = &expr.kind
602 && segments.len() == 1
603 {
604 while let token::Ident(..) | token::Literal(_) | token::Dot =
605 self.parser.token.kind
606 {
607 self.parser.bump();
610 }
611 err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
612 before: expr.span.shrink_to_lo(),
613 after: self.parser.prev_token.span.shrink_to_hi(),
614 });
615 }
616 }
617 Ok(None) => {}
618 Err(e) => {
619 e.cancel();
620 self.parser.restore_snapshot(snapshot);
621 }
622 }
623
624 self.parser.dcx().create_err(err)
625 }
626
627 fn parse(
628 tokens: TokenStream,
629 psess: &'sess ParseSess,
630 span: Span,
631 should_emit: ShouldEmit,
632 allow_expr_metavar: AllowExprMetavar,
633 ) -> PResult<'sess, MetaItemListParser> {
634 let mut parser = Parser::new(psess, tokens, None);
635 if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
636 parser = parser.recovery(recovery);
637 }
638
639 let mut this =
640 MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
641
642 let mut sub_parsers = ThinVec::with_capacity(1);
644 while this.parser.token != token::Eof {
645 sub_parsers.push(this.parse_meta_item_inner()?);
646
647 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)) {
648 break;
649 }
650 }
651
652 if parser.token != token::Eof {
653 parser.unexpected()?;
654 }
655
656 Ok(MetaItemListParser { sub_parsers, span })
657 }
658}
659
660#[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, #[automatically_derived]
impl ::core::clone::Clone for MetaItemListParser {
#[inline]
fn clone(&self) -> MetaItemListParser {
MetaItemListParser {
sub_parsers: ::core::clone::Clone::clone(&self.sub_parsers),
span: ::core::clone::Clone::clone(&self.span),
}
}
}Clone)]
661pub struct MetaItemListParser {
662 sub_parsers: ThinVec<MetaItemOrLitParser>,
663 pub span: Span,
664}
665
666impl MetaItemListParser {
667 pub(crate) fn new<'sess>(
668 tokens: &TokenStream,
669 span: Span,
670 psess: &'sess ParseSess,
671 should_emit: ShouldEmit,
672 allow_expr_metavar: AllowExprMetavar,
673 ) -> Result<Self, Diag<'sess>> {
674 MetaItemListParserContext::parse(
675 tokens.clone(),
676 psess,
677 span,
678 should_emit,
679 allow_expr_metavar,
680 )
681 }
682
683 pub fn mixed(&self) -> impl Iterator<Item = &MetaItemOrLitParser> {
685 self.sub_parsers.iter()
686 }
687
688 pub fn len(&self) -> usize {
689 self.sub_parsers.len()
690 }
691
692 pub fn is_empty(&self) -> bool {
693 self.len() == 0
694 }
695
696 pub fn as_single(&self) -> Option<&MetaItemOrLitParser> {
700 let mut iter = self.mixed();
701 iter.next().filter(|_| iter.next().is_none())
702 }
703}