1use std::ops::Range;
2
3use rustc_hir::attrs::diagnostic::{
4 Directive, Filter, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name,
5 NameValue, Piece, Predicate,
6};
7use rustc_parse_format::{
8 Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
9};
10use rustc_session::lint::builtin::{
11 MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FILTERS,
12 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
13};
14use rustc_span::{Ident, InnerSpan, Span, Symbol, kw, sym};
15use thin_vec::{ThinVec, thin_vec};
16
17use crate::context::AcceptContext;
18use crate::diagnostics::{
19 FormatWarning, IgnoredDiagnosticOption, InvalidOnClause, MalFormedDiagnosticAttributeLint,
20 MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError,
21};
22use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
23
24pub(crate) mod do_not_recommend;
25pub(crate) mod on_const;
26pub(crate) mod on_move;
27pub(crate) mod on_type_error;
28pub(crate) mod on_unimplemented;
29pub(crate) mod on_unknown;
30pub(crate) mod on_unmatched_args;
31pub(crate) mod opaque;
32
33#[derive(#[automatically_derived]
impl ::core::marker::Copy for Mode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Mode {
#[inline]
fn clone(&self) -> Mode { *self }
}Clone)]
34pub(crate) enum Mode {
35 RustcOnUnimplemented,
37 DiagnosticOnUnimplemented,
39 DiagnosticOnConst,
41 DiagnosticOnMove,
43 DiagnosticOnUnknown,
45 DiagnosticOnUnmatchedArgs,
47 DiagnosticOnTypeError,
49}
50
51impl Mode {
52 fn as_str(self) -> &'static str {
53 match self {
54 Self::RustcOnUnimplemented => "rustc_on_unimplemented",
55 Self::DiagnosticOnUnimplemented => "diagnostic::on_unimplemented",
56 Self::DiagnosticOnConst => "diagnostic::on_const",
57 Self::DiagnosticOnMove => "diagnostic::on_move",
58 Self::DiagnosticOnUnknown => "diagnostic::on_unknown",
59 Self::DiagnosticOnUnmatchedArgs => "diagnostic::on_unmatched_args",
60 Self::DiagnosticOnTypeError => "diagnostic::on_type_error",
61 }
62 }
63
64 fn expected_options(self) -> &'static str {
65 const DEFAULT: &str =
66 "at least one of the `message`, `note` and `label` options are expected";
67 const DIAGNOSTIC_ON_TYPE_ERROR_EXPECTED_OPTIONS: &str =
68 "at least a single `note` option is expected";
69 match self {
70 Self::RustcOnUnimplemented => {
71 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
72 }
73 Self::DiagnosticOnUnimplemented
74 | Self::DiagnosticOnConst
75 | Self::DiagnosticOnMove
76 | Self::DiagnosticOnUnknown
77 | Self::DiagnosticOnUnmatchedArgs => DEFAULT,
78 Self::DiagnosticOnTypeError => DIAGNOSTIC_ON_TYPE_ERROR_EXPECTED_OPTIONS,
79 }
80 }
81
82 fn allowed_options(self) -> &'static str {
83 const DEFAULT: &str = "only `message`, `note` and `label` are allowed as options";
84 const DIAGNOSTIC_ON_TYPE_ERROR_ALLOWED_OPTIONS: &str =
85 "only `note` is allowed as option for `diagnostic::on_type_error`";
86 match self {
87 Self::RustcOnUnimplemented => {
88 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
89 }
90 Self::DiagnosticOnUnimplemented
91 | Self::DiagnosticOnConst
92 | Self::DiagnosticOnMove
93 | Self::DiagnosticOnUnknown
94 | Self::DiagnosticOnUnmatchedArgs => DEFAULT,
95 Self::DiagnosticOnTypeError => DIAGNOSTIC_ON_TYPE_ERROR_ALLOWED_OPTIONS,
96 }
97 }
98
99 fn allowed_format_arguments(self) -> &'static str {
100 match self {
101 Self::RustcOnUnimplemented => {
102 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented> for allowed format arguments"
103 }
104 Self::DiagnosticOnUnimplemented => {
105 "only `Self` and generics of the trait are allowed as a format argument"
106 }
107 Self::DiagnosticOnConst => {
108 "only `Self` and generics of the implementation are allowed as a format argument"
109 }
110 Self::DiagnosticOnMove => {
111 "only `This`, `Self` and generics of the type are allowed as a format argument"
112 }
113 Self::DiagnosticOnUnknown => {
114 "only `This` is allowed as a format argument, referring to the failed import"
115 }
116 Self::DiagnosticOnUnmatchedArgs => {
117 "only `This` is allowed as a format argument, referring to the macro's name"
118 }
119 Self::DiagnosticOnTypeError => {
120 "only `note` is allowed as option for `diagnostic::on_type_error`"
121 }
122 }
123 }
124}
125
126fn merge_directives(
127 cx: &mut AcceptContext<'_, '_>,
128 first: &mut Option<(Span, Directive)>,
129 later: (Span, Directive),
130) {
131 if let Some((_, first)) = first {
132 let Directive { is_rustc_attr, filters, message, label, notes, parent_label } = later.1;
133
134 first.is_rustc_attr |= is_rustc_attr;
135 first.filters.extend(filters);
136 merge(cx, &mut first.message, message, sym::message);
137 merge(cx, &mut first.label, label, sym::label);
138 first.notes.extend(notes);
139 merge(cx, &mut first.parent_label, parent_label, sym::parent_label);
140 } else {
141 *first = Some(later);
142 }
143}
144
145fn merge<T>(
146 cx: &mut AcceptContext<'_, '_>,
147 first: &mut Option<(Span, T)>,
148 later: Option<(Span, T)>,
149 option_name: Symbol,
150) {
151 match (first, later) {
152 (Some(_) | None, None) => {}
153 (Some((first_span, _)), Some((later_span, _))) => {
154 let first_span = *first_span;
155 cx.emit_lint(
156 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
157 IgnoredDiagnosticOption { first_span, later_span, option_name },
158 later_span,
159 );
160 }
161 (first @ None, Some(later)) => {
162 first.get_or_insert(later);
163 }
164 }
165}
166
167fn parse_list<'p>(
168 cx: &mut AcceptContext<'_, '_>,
169 args: &'p ArgParser,
170 mode: Mode,
171) -> Option<&'p MetaItemListParser> {
172 let span = cx.attr_span;
173 match args {
174 ArgParser::List(items) if items.len() != 0 => return Some(items),
175 ArgParser::List(list) => {
176 cx.emit_lint(
180 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
181 NonMetaItemDiagnosticAttribute,
182 list.span,
183 );
184 }
185 ArgParser::NoArgs => {
186 cx.emit_lint(
187 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
188 MissingOptionsForDiagnosticAttribute {
189 attribute: mode.as_str(),
190 options: mode.expected_options(),
191 },
192 span,
193 );
194 }
195 ArgParser::NameValue(_) => {
196 cx.emit_lint(
197 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
198 MalFormedDiagnosticAttributeLint {
199 attribute: mode.as_str(),
200 options: mode.allowed_options(),
201 span,
202 },
203 span,
204 );
205 }
206 }
207 None
208}
209
210fn parse_directive_items<'p>(
211 cx: &mut AcceptContext<'_, '_>,
212 mode: Mode,
213 items: impl Iterator<Item = &'p MetaItemOrLitParser>,
214 is_root: bool,
215) -> Option<Directive> {
216 let mut message: Option<(Span, _)> = None;
217 let mut label: Option<(Span, _)> = None;
218 let mut notes = ThinVec::new();
219 let mut parent_label: Option<(Span, FormatString)> = None;
220 let mut filters = ThinVec::new();
221
222 for item in items {
223 let span = item.span();
224
225 macro malformed() {{
226 cx.emit_lint(
227 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
228 MalFormedDiagnosticAttributeLint {
229 attribute: mode.as_str(),
230 options: mode.allowed_options(),
231 span,
232 },
233 span,
234 );
235 continue;
236 }}
237
238 macro or_malformed($($code:tt)*) {{
239 let Some(ret) = (
240 try {
241 $($code)*
242 }
243 ) else {
244 malformed!()
245 };
246 ret
247 }}
248
249 macro duplicate($name: ident, $($first_span:tt)*) {{
250 let first_span = $($first_span)*;
251 cx.emit_lint(
252 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
253 IgnoredDiagnosticOption {
254 first_span,
255 later_span: span,
256 option_name: $name,
257 },
258 span,
259 );
260 }}
261
262 let item: &MetaItemParser = {
let Some(ret) =
(try {
item.meta_item()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(item.meta_item()?);
263 let name = {
let Some(ret) =
(try {
item.ident()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(item.ident()?).name;
264
265 let value: Option<Ident> = match item.args().as_name_value() {
273 Some(nv) => Some({
let Some(ret) =
(try {
nv.value_as_ident()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(nv.value_as_ident()?)),
274 None => None,
275 };
276
277 let mut parse_format = |input: Ident| {
278 let snippet = cx.sess.source_map().span_to_snippet(input.span).ok();
279 let is_snippet = snippet.is_some();
280 match parse_format_string(input.name, snippet, input.span, mode) {
281 Ok((f, warnings)) => {
282 for warning in warnings {
283 let (FormatWarning::InvalidSpecifier { span }
284 | FormatWarning::PositionalArgument { span }
285 | FormatWarning::IndexedArgument { span }
286 | FormatWarning::DisallowedPlaceholder { span, .. }) = warning;
287 cx.emit_lint(MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, warning, span);
288 }
289
290 f
291 }
292 Err(e) => {
293 cx.emit_lint(
294 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
295 WrappedParserError {
296 description: e.description,
297 label: e.label,
298 span: slice_span(input.span, e.span.clone(), is_snippet),
299 },
300 input.span,
301 );
302 FormatString {
304 input: input.name,
305 span: input.span,
306 pieces: {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(Piece::Lit(input.name));
vec
}thin_vec![Piece::Lit(input.name)],
307 }
308 }
309 }
310 };
311 match (mode, name) {
312 (
313 Mode::RustcOnUnimplemented
314 | Mode::DiagnosticOnUnimplemented
315 | Mode::DiagnosticOnConst
316 | Mode::DiagnosticOnMove
317 | Mode::DiagnosticOnUnknown
318 | Mode::DiagnosticOnUnmatchedArgs,
319 sym::message,
320 ) => {
321 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(value?);
322 if let Some(message) = &message {
323 {
let first_span = message.0;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}, span);
}duplicate!(name, message.0)
324 } else {
325 message = Some((item.span(), parse_format(value)));
326 }
327 }
328 (
329 Mode::RustcOnUnimplemented
330 | Mode::DiagnosticOnUnimplemented
331 | Mode::DiagnosticOnConst
332 | Mode::DiagnosticOnMove
333 | Mode::DiagnosticOnUnknown
334 | Mode::DiagnosticOnUnmatchedArgs,
335 sym::label,
336 ) => {
337 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(value?);
338 if let Some(label) = &label {
339 {
let first_span = label.0;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}, span);
}duplicate!(name, label.0)
340 } else {
341 label = Some((item.span(), parse_format(value)));
342 }
343 }
344 (_, sym::note) => {
345 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(value?);
346 notes.push(parse_format(value))
347 }
348 (Mode::RustcOnUnimplemented, sym::parent_label) => {
349 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(value?);
350 if let Some(parent_label) = &parent_label {
351 {
let first_span = parent_label.0;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}, span);
}duplicate!(name, parent_label.0)
352 } else {
353 let format = parse_format(value);
354 parent_label = Some((format.span, format));
355 }
356 }
357 (Mode::RustcOnUnimplemented, sym::on) => {
358 if is_root {
359 let items = {
let Some(ret) =
(try {
item.args().as_list()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(item.args().as_list()?);
360 let mut iter = items.mixed();
361 let filter = if let Some(c) = iter.next() {
362 c
363 } else {
364 cx.emit_lint(
365 MALFORMED_DIAGNOSTIC_FILTERS,
366 InvalidOnClause::Empty { span },
367 span,
368 );
369 continue;
370 };
371
372 let filter = parse_filter(filter);
373
374 if items.len() < 2 {
375 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
378 }
379
380 match filter {
381 Ok(filter) => {
382 let directive =
383 {
let Some(ret) =
(try {
parse_directive_items(cx, mode, iter, false)?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
}
};
ret
}or_malformed!(parse_directive_items(cx, mode, iter, false)?);
384 filters.push((filter, directive));
385 }
386 Err(e) => {
387 cx.emit_lint(MALFORMED_DIAGNOSTIC_FILTERS, e, span);
388 }
389 }
390 } else {
391 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
392 }
393 }
394 _other => {
395 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
396 }
397 }
398 }
399
400 Some(Directive {
401 is_rustc_attr: #[allow(non_exhaustive_omitted_patterns)] match mode {
Mode::RustcOnUnimplemented => true,
_ => false,
}matches!(mode, Mode::RustcOnUnimplemented),
402 filters,
403 message,
404 label,
405 notes,
406 parent_label,
407 })
408}
409
410pub(crate) fn parse_format_string(
411 input: Symbol,
412 snippet: Option<String>,
413 span: Span,
414 mode: Mode,
415) -> Result<(FormatString, Vec<FormatWarning>), ParseError> {
416 let s = input.as_str();
417 let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
418 let pieces: Vec<_> = parser.by_ref().collect();
419
420 if let Some(err) = parser.errors.into_iter().next() {
421 return Err(err);
422 }
423 let mut warnings = Vec::new();
424
425 let pieces = pieces
426 .into_iter()
427 .map(|piece| match piece {
428 RpfPiece::Lit(lit) => Piece::Lit(Symbol::intern(lit)),
429 RpfPiece::NextArgument(arg) => {
430 Piece::Arg(parse_arg(&arg, mode, &mut warnings, span, parser.is_source_literal))
431 }
432 })
433 .collect();
434
435 Ok((FormatString { input, pieces, span }, warnings))
436}
437
438fn parse_arg(
439 arg: &Argument<'_>,
440 mode: Mode,
441 warnings: &mut Vec<FormatWarning>,
442 input_span: Span,
443 is_source_literal: bool,
444) -> FormatArg {
445 let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
446
447 let mut check_format = true;
448
449 let ret = match arg.position {
450 Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
452 (Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext,
453
454 (Mode::RustcOnUnimplemented, sym::This) => match arg.format.ty {
456 "resolved" => {
457 check_format = false;
458 FormatArg::ThisResolved
459 }
460 "path" => {
461 check_format = false;
462 FormatArg::ThisPath
463 }
464 _ => FormatArg::This,
465 },
466
467 (Mode::DiagnosticOnTypeError, sym::Found) => FormatArg::Found,
468 (Mode::DiagnosticOnTypeError, sym::Expected) => FormatArg::Expected,
469 (Mode::DiagnosticOnUnknown, sym::Unresolved) => FormatArg::Unresolved,
470
471 (
477 Mode::DiagnosticOnUnknown
478 | Mode::DiagnosticOnMove
479 | Mode::DiagnosticOnUnmatchedArgs
480 | Mode::DiagnosticOnTypeError,
481 sym::This,
482 ) => FormatArg::This,
483
484 (
490 Mode::RustcOnUnimplemented
491 | Mode::DiagnosticOnUnimplemented
492 | Mode::DiagnosticOnMove
493 | Mode::DiagnosticOnConst,
494 kw::SelfUpper,
495 ) => FormatArg::SelfUpper,
496
497 (
503 Mode::RustcOnUnimplemented
504 | Mode::DiagnosticOnUnimplemented
505 | Mode::DiagnosticOnMove
506 | Mode::DiagnosticOnConst
507 | Mode::DiagnosticOnTypeError,
508 generic_param,
509 ) => FormatArg::GenericParam { generic_param, span },
510
511 (Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchedArgs, as_is) => {
513 warnings.push(FormatWarning::DisallowedPlaceholder {
514 span,
515 attr: mode.as_str(),
516 allowed: mode.allowed_format_arguments(),
517 });
518 FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", as_is))
})format!("{{{as_is}}}")))
519 }
520 },
521
522 Position::ArgumentIs(idx) => {
524 warnings.push(FormatWarning::IndexedArgument { span });
525 FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}")))
526 }
527 Position::ArgumentImplicitlyIs(_) => {
528 warnings.push(FormatWarning::PositionalArgument { span });
529 FormatArg::AsIs(sym::empty_braces)
530 }
531 };
532 if check_format {
533 warn_on_format_spec(&arg.format, warnings, input_span, is_source_literal);
534 }
535 ret
536}
537
538fn warn_on_format_spec(
541 spec: &FormatSpec<'_>,
542 warnings: &mut Vec<FormatWarning>,
543 input_span: Span,
544 is_source_literal: bool,
545) {
546 if let Some(ty_span) = &spec.ty_span {
547 let span = slice_span(input_span, ty_span.clone(), is_source_literal);
548 warnings.push(FormatWarning::InvalidSpecifier { span })
549 }
550}
551
552fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
553 if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
554}
555
556pub(crate) fn parse_filter(input: &MetaItemOrLitParser) -> Result<Filter, InvalidOnClause> {
557 let span = input.span();
558 let pred = parse_predicate(input)?;
559 Ok(Filter { span, pred })
560}
561
562fn parse_predicate(input: &MetaItemOrLitParser) -> Result<Predicate, InvalidOnClause> {
563 let Some(meta_item) = input.meta_item() else {
564 return Err(InvalidOnClause::UnsupportedLiteral { span: input.span() });
565 };
566
567 let Some(predicate) = meta_item.ident() else {
568 return Err(InvalidOnClause::ExpectedIdentifier {
569 span: meta_item.path().span(),
570 path: meta_item.path().get_attribute_path(),
571 });
572 };
573
574 match meta_item.args() {
575 ArgParser::List(mis) => match predicate.name {
576 sym::any => Ok(Predicate::Any(parse_predicate_sequence(mis)?)),
577 sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)),
578 sym::not => {
579 if let Some(single) = mis.as_single() {
580 Ok(Predicate::Not(Box::new(parse_predicate(single)?)))
581 } else {
582 Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span })
583 }
584 }
585 invalid_pred => {
586 Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred })
587 }
588 },
589 ArgParser::NameValue(p) => {
590 let Some(value) = p.value_as_ident() else {
591 return Err(InvalidOnClause::UnsupportedLiteral { span: p.args_span() });
592 };
593 let name = parse_name(predicate.name);
594 let value = parse_filter_format(value.name);
595 let kv = NameValue { name, value };
596 Ok(Predicate::Match(kv))
597 }
598 ArgParser::NoArgs => {
599 let flag = parse_flag(predicate)?;
600 Ok(Predicate::Flag(flag))
601 }
602 }
603}
604
605fn parse_predicate_sequence(
606 sequence: &MetaItemListParser,
607) -> Result<ThinVec<Predicate>, InvalidOnClause> {
608 sequence.mixed().map(parse_predicate).collect()
609}
610
611fn parse_flag(Ident { name, span }: Ident) -> Result<Flag, InvalidOnClause> {
612 match name {
613 sym::crate_local => Ok(Flag::CrateLocal),
614 sym::direct => Ok(Flag::Direct),
615 sym::from_desugaring => Ok(Flag::FromDesugaring),
616 invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }),
617 }
618}
619
620fn parse_name(name: Symbol) -> Name {
621 match name {
622 kw::SelfUpper => Name::SelfUpper,
623 sym::from_desugaring => Name::FromDesugaring,
624 sym::cause => Name::Cause,
625 generic => Name::GenericArg(generic),
626 }
627}
628
629fn parse_filter_format(input: Symbol) -> FilterFormatString {
630 let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
631 .map(|p| match p {
632 RpfPiece::Lit(s) => LitOrArg::Lit(Symbol::intern(s)),
633 RpfPiece::NextArgument(a) => match a.position {
635 Position::ArgumentNamed(
643 arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
644 ) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", arg))
})format!("{{{arg}}}"))),
645
646 Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
647 Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
648 Position::ArgumentIs(idx) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}"))),
649 },
650 })
651 .collect();
652 FilterFormatString { pieces }
653}