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