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;
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 => DEFAULT,
74 Self::DiagnosticOnConst => DEFAULT,
75 Self::DiagnosticOnMove => DEFAULT,
76 Self::DiagnosticOnUnknown => DEFAULT,
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 => DEFAULT,
91 Self::DiagnosticOnConst => DEFAULT,
92 Self::DiagnosticOnMove => DEFAULT,
93 Self::DiagnosticOnUnknown => DEFAULT,
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 if first.is_rustc_attr || later.1.is_rustc_attr {
133 cx.emit_err(DupesNotAllowed);
134 }
135
136 merge(cx, &mut first.message, later.1.message, sym::message);
137 merge(cx, &mut first.label, later.1.label, sym::label);
138 first.notes.extend(later.1.notes);
139 } else {
140 *first = Some(later);
141 }
142}
143
144fn merge<T>(
145 cx: &mut AcceptContext<'_, '_>,
146 first: &mut Option<(Span, T)>,
147 later: Option<(Span, T)>,
148 option_name: Symbol,
149) {
150 match (first, later) {
151 (Some(_) | None, None) => {}
152 (Some((first_span, _)), Some((later_span, _))) => {
153 let first_span = *first_span;
154 cx.emit_lint(
155 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
156 IgnoredDiagnosticOption { first_span, later_span, option_name },
157 later_span,
158 );
159 }
160 (first @ None, Some(later)) => {
161 first.get_or_insert(later);
162 }
163 }
164}
165
166fn parse_list<'p>(
167 cx: &mut AcceptContext<'_, '_>,
168 args: &'p ArgParser,
169 mode: Mode,
170) -> Option<&'p MetaItemListParser> {
171 let span = cx.attr_span;
172 match args {
173 ArgParser::List(items) if items.len() != 0 => return Some(items),
174 ArgParser::List(list) => {
175 cx.emit_lint(
179 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
180 NonMetaItemDiagnosticAttribute,
181 list.span,
182 );
183 }
184 ArgParser::NoArgs => {
185 cx.emit_lint(
186 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
187 MissingOptionsForDiagnosticAttribute {
188 attribute: mode.as_str(),
189 options: mode.expected_options(),
190 },
191 span,
192 );
193 }
194 ArgParser::NameValue(_) => {
195 cx.emit_lint(
196 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
197 MalFormedDiagnosticAttributeLint {
198 attribute: mode.as_str(),
199 options: mode.allowed_options(),
200 span,
201 },
202 span,
203 );
204 }
205 }
206 None
207}
208
209fn parse_directive_items<'p>(
210 cx: &mut AcceptContext<'_, '_>,
211 mode: Mode,
212 items: impl Iterator<Item = &'p MetaItemOrLitParser>,
213 is_root: bool,
214) -> Option<Directive> {
215 let mut message: Option<(Span, _)> = None;
216 let mut label: Option<(Span, _)> = None;
217 let mut notes = ThinVec::new();
218 let mut parent_label = None;
219 let mut filters = ThinVec::new();
220
221 for item in items {
222 let span = item.span();
223
224 macro malformed() {{
225 cx.emit_lint(
226 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
227 MalFormedDiagnosticAttributeLint {
228 attribute: mode.as_str(),
229 options: mode.allowed_options(),
230 span,
231 },
232 span,
233 );
234 continue;
235 }}
236
237 macro or_malformed($($code:tt)*) {{
238 let Some(ret) = (
239 try {
240 $($code)*
241 }
242 ) else {
243 malformed!()
244 };
245 ret
246 }}
247
248 macro duplicate($name: ident, $($first_span:tt)*) {{
249 let first_span = $($first_span)*;
250 cx.emit_lint(
251 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
252 IgnoredDiagnosticOption {
253 first_span,
254 later_span: span,
255 option_name: $name,
256 },
257 span,
258 );
259 }}
260
261 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()?);
262 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;
263
264 let value: Option<Ident> = match item.args().as_name_value() {
272 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()?)),
273 None => None,
274 };
275
276 let mut parse_format = |input: Ident| {
277 let snippet = cx.sess.source_map().span_to_snippet(input.span).ok();
278 let is_snippet = snippet.is_some();
279 match parse_format_string(input.name, snippet, input.span, mode) {
280 Ok((f, warnings)) => {
281 for warning in warnings {
282 let (FormatWarning::InvalidSpecifier { span }
283 | FormatWarning::PositionalArgument { span }
284 | FormatWarning::IndexedArgument { span }
285 | FormatWarning::DisallowedPlaceholder { span, .. }) = warning;
286 cx.emit_lint(MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, warning, span);
287 }
288
289 f
290 }
291 Err(e) => {
292 cx.emit_lint(
293 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
294 WrappedParserError {
295 description: e.description,
296 label: e.label,
297 span: slice_span(input.span, e.span.clone(), is_snippet),
298 },
299 input.span,
300 );
301 FormatString {
303 input: input.name,
304 span: input.span,
305 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)],
306 }
307 }
308 }
309 };
310 match (mode, name) {
311 (
312 Mode::RustcOnUnimplemented
313 | Mode::DiagnosticOnUnimplemented
314 | Mode::DiagnosticOnConst
315 | Mode::DiagnosticOnMove
316 | Mode::DiagnosticOnUnknown
317 | Mode::DiagnosticOnUnmatchedArgs,
318 sym::message,
319 ) => {
320 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?);
321 if let Some(message) = &message {
322 {
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)
323 } else {
324 message = Some((item.span(), parse_format(value)));
325 }
326 }
327 (
328 Mode::RustcOnUnimplemented
329 | Mode::DiagnosticOnUnimplemented
330 | Mode::DiagnosticOnConst
331 | Mode::DiagnosticOnMove
332 | Mode::DiagnosticOnUnknown
333 | Mode::DiagnosticOnUnmatchedArgs,
334 sym::label,
335 ) => {
336 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?);
337 if let Some(label) = &label {
338 {
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)
339 } else {
340 label = Some((item.span(), parse_format(value)));
341 }
342 }
343 (_, sym::note) => {
344 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?);
345 notes.push(parse_format(value))
346 }
347 (Mode::RustcOnUnimplemented, sym::parent_label) => {
348 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?);
349 if parent_label.is_none() {
350 parent_label = Some(parse_format(value));
351 } else {
352 {
let first_span = span;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}, span);
}duplicate!(name, span)
353 }
354 }
355 (Mode::RustcOnUnimplemented, sym::on) => {
356 if is_root {
357 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()?);
358 let mut iter = items.mixed();
359 let filter: &MetaItemOrLitParser = match iter.next() {
360 Some(c) => c,
361 None => {
362 cx.emit_err(InvalidOnClause::Empty { span });
363 continue;
364 }
365 };
366
367 let filter = parse_filter(filter);
368
369 if items.len() < 2 {
370 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
373 }
374
375 match filter {
376 Ok(filter) => {
377 let directive =
378 {
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)?);
379 filters.push((filter, directive));
380 }
381 Err(e) => {
382 cx.emit_err(e);
383 }
384 }
385 } else {
386 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
387 }
388 }
389 _other => {
390 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}, span);
continue;
};malformed!();
391 }
392 }
393 }
394
395 Some(Directive {
396 is_rustc_attr: #[allow(non_exhaustive_omitted_patterns)] match mode {
Mode::RustcOnUnimplemented => true,
_ => false,
}matches!(mode, Mode::RustcOnUnimplemented),
397 filters,
398 message,
399 label,
400 notes,
401 parent_label,
402 })
403}
404
405pub(crate) fn parse_format_string(
406 input: Symbol,
407 snippet: Option<String>,
408 span: Span,
409 mode: Mode,
410) -> Result<(FormatString, Vec<FormatWarning>), ParseError> {
411 let s = input.as_str();
412 let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
413 let pieces: Vec<_> = parser.by_ref().collect();
414
415 if let Some(err) = parser.errors.into_iter().next() {
416 return Err(err);
417 }
418 let mut warnings = Vec::new();
419
420 let pieces = pieces
421 .into_iter()
422 .map(|piece| match piece {
423 RpfPiece::Lit(lit) => Piece::Lit(Symbol::intern(lit)),
424 RpfPiece::NextArgument(arg) => {
425 Piece::Arg(parse_arg(&arg, mode, &mut warnings, span, parser.is_source_literal))
426 }
427 })
428 .collect();
429
430 Ok((FormatString { input, pieces, span }, warnings))
431}
432
433fn parse_arg(
434 arg: &Argument<'_>,
435 mode: Mode,
436 warnings: &mut Vec<FormatWarning>,
437 input_span: Span,
438 is_source_literal: bool,
439) -> FormatArg {
440 let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
441
442 let mut check_format = true;
443
444 let ret = match arg.position {
445 Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
447 (Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext,
448
449 (Mode::RustcOnUnimplemented, sym::This) => match arg.format.ty {
451 "resolved" => {
452 check_format = false;
453 FormatArg::ThisResolved
454 }
455 "path" => {
456 check_format = false;
457 FormatArg::ThisPath
458 }
459 _ => FormatArg::This,
460 },
461
462 (Mode::DiagnosticOnTypeError, sym::Found) => FormatArg::Found,
463 (Mode::DiagnosticOnTypeError, sym::Expected) => FormatArg::Expected,
464 (Mode::DiagnosticOnUnknown, sym::Unresolved) => FormatArg::Unresolved,
465
466 (
472 Mode::DiagnosticOnUnknown
473 | Mode::DiagnosticOnMove
474 | Mode::DiagnosticOnUnmatchedArgs
475 | Mode::DiagnosticOnTypeError,
476 sym::This,
477 ) => FormatArg::This,
478
479 (
485 Mode::RustcOnUnimplemented
486 | Mode::DiagnosticOnUnimplemented
487 | Mode::DiagnosticOnMove
488 | Mode::DiagnosticOnConst,
489 kw::SelfUpper,
490 ) => FormatArg::SelfUpper,
491
492 (
498 Mode::RustcOnUnimplemented
499 | Mode::DiagnosticOnUnimplemented
500 | Mode::DiagnosticOnMove
501 | Mode::DiagnosticOnConst
502 | Mode::DiagnosticOnTypeError,
503 generic_param,
504 ) => FormatArg::GenericParam { generic_param, span },
505
506 (Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchedArgs, as_is) => {
508 warnings.push(FormatWarning::DisallowedPlaceholder {
509 span,
510 attr: mode.as_str(),
511 allowed: mode.allowed_format_arguments(),
512 });
513 FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", as_is))
})format!("{{{as_is}}}")))
514 }
515 },
516
517 Position::ArgumentIs(idx) => {
519 warnings.push(FormatWarning::IndexedArgument { span });
520 FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}")))
521 }
522 Position::ArgumentImplicitlyIs(_) => {
523 warnings.push(FormatWarning::PositionalArgument { span });
524 FormatArg::AsIs(sym::empty_braces)
525 }
526 };
527 if check_format {
528 warn_on_format_spec(&arg.format, warnings, input_span, is_source_literal);
529 }
530 ret
531}
532
533fn warn_on_format_spec(
536 spec: &FormatSpec<'_>,
537 warnings: &mut Vec<FormatWarning>,
538 input_span: Span,
539 is_source_literal: bool,
540) {
541 if let Some(ty_span) = &spec.ty_span {
542 let span = slice_span(input_span, ty_span.clone(), is_source_literal);
543 warnings.push(FormatWarning::InvalidSpecifier { span })
544 }
545}
546
547fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
548 if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
549}
550
551pub(crate) fn parse_filter(input: &MetaItemOrLitParser) -> Result<Filter, InvalidOnClause> {
552 let span = input.span();
553 let pred = parse_predicate(input)?;
554 Ok(Filter { span, pred })
555}
556
557fn parse_predicate(input: &MetaItemOrLitParser) -> Result<Predicate, InvalidOnClause> {
558 let Some(meta_item) = input.meta_item() else {
559 return Err(InvalidOnClause::UnsupportedLiteral { span: input.span() });
560 };
561
562 let Some(predicate) = meta_item.ident() else {
563 return Err(InvalidOnClause::ExpectedIdentifier {
564 span: meta_item.path().span(),
565 path: meta_item.path().get_attribute_path(),
566 });
567 };
568
569 match meta_item.args() {
570 ArgParser::List(mis) => match predicate.name {
571 sym::any => Ok(Predicate::Any(parse_predicate_sequence(mis)?)),
572 sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)),
573 sym::not => {
574 if let Some(single) = mis.as_single() {
575 Ok(Predicate::Not(Box::new(parse_predicate(single)?)))
576 } else {
577 Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span })
578 }
579 }
580 invalid_pred => {
581 Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred })
582 }
583 },
584 ArgParser::NameValue(p) => {
585 let Some(value) = p.value_as_ident() else {
586 return Err(InvalidOnClause::UnsupportedLiteral { span: p.args_span() });
587 };
588 let name = parse_name(predicate.name);
589 let value = parse_filter_format(value.name);
590 let kv = NameValue { name, value };
591 Ok(Predicate::Match(kv))
592 }
593 ArgParser::NoArgs => {
594 let flag = parse_flag(predicate)?;
595 Ok(Predicate::Flag(flag))
596 }
597 }
598}
599
600fn parse_predicate_sequence(
601 sequence: &MetaItemListParser,
602) -> Result<ThinVec<Predicate>, InvalidOnClause> {
603 sequence.mixed().map(parse_predicate).collect()
604}
605
606fn parse_flag(Ident { name, span }: Ident) -> Result<Flag, InvalidOnClause> {
607 match name {
608 sym::crate_local => Ok(Flag::CrateLocal),
609 sym::direct => Ok(Flag::Direct),
610 sym::from_desugaring => Ok(Flag::FromDesugaring),
611 invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }),
612 }
613}
614
615fn parse_name(name: Symbol) -> Name {
616 match name {
617 kw::SelfUpper => Name::SelfUpper,
618 sym::from_desugaring => Name::FromDesugaring,
619 sym::cause => Name::Cause,
620 generic => Name::GenericArg(generic),
621 }
622}
623
624fn parse_filter_format(input: Symbol) -> FilterFormatString {
625 let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
626 .map(|p| match p {
627 RpfPiece::Lit(s) => LitOrArg::Lit(Symbol::intern(s)),
628 RpfPiece::NextArgument(a) => match a.position {
630 Position::ArgumentNamed(
638 arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
639 ) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", arg))
})format!("{{{arg}}}"))),
640
641 Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
642 Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
643 Position::ArgumentIs(idx) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}"))),
644 },
645 })
646 .collect();
647 FilterFormatString { pieces }
648}