1use std::ops::Range;
2
3use rustc_errors::{Diagnostic, E0232};
4use rustc_hir::AttrPath;
5use rustc_hir::attrs::diagnostic::{
6 Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue,
7 OnUnimplementedCondition, Piece, Predicate,
8};
9use rustc_macros::Diagnostic;
10use rustc_parse_format::{
11 Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
12};
13use rustc_session::lint::builtin::{
14 MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
15};
16use rustc_span::{Ident, InnerSpan, Span, Symbol, kw, sym};
17use thin_vec::{ThinVec, thin_vec};
18
19use crate::context::AcceptContext;
20use crate::errors::{
21 FormatWarning, IgnoredDiagnosticOption, MalFormedDiagnosticAttributeLint,
22 MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError,
23};
24use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
25
26pub(crate) mod check_cfg;
27pub(crate) mod do_not_recommend;
28pub(crate) mod on_const;
29pub(crate) mod on_move;
30pub(crate) mod on_unimplemented;
31pub(crate) mod on_unknown;
32pub(crate) mod on_unmatch_args;
33
34#[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)]
35pub(crate) enum Mode {
36 RustcOnUnimplemented,
38 DiagnosticOnUnimplemented,
40 DiagnosticOnConst,
42 DiagnosticOnMove,
44 DiagnosticOnUnknown,
46 DiagnosticOnUnmatchArgs,
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::DiagnosticOnUnmatchArgs => "diagnostic::on_unmatch_args",
59 }
60 }
61
62 fn expected_options(&self) -> &'static str {
63 const DEFAULT: &str =
64 "at least one of the `message`, `note` and `label` options are expected";
65 match self {
66 Self::RustcOnUnimplemented => {
67 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
68 }
69 Self::DiagnosticOnUnimplemented => DEFAULT,
70 Self::DiagnosticOnConst => DEFAULT,
71 Self::DiagnosticOnMove => DEFAULT,
72 Self::DiagnosticOnUnknown => DEFAULT,
73 Self::DiagnosticOnUnmatchArgs => DEFAULT,
74 }
75 }
76
77 fn allowed_options(&self) -> &'static str {
78 const DEFAULT: &str = "only `message`, `note` and `label` are allowed as options";
79 match self {
80 Self::RustcOnUnimplemented => {
81 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
82 }
83 Self::DiagnosticOnUnimplemented => DEFAULT,
84 Self::DiagnosticOnConst => DEFAULT,
85 Self::DiagnosticOnMove => DEFAULT,
86 Self::DiagnosticOnUnknown => DEFAULT,
87 Self::DiagnosticOnUnmatchArgs => DEFAULT,
88 }
89 }
90
91 fn allowed_format_arguments(&self) -> &'static str {
92 match self {
93 Self::RustcOnUnimplemented => {
94 "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented> for allowed format arguments"
95 }
96 Self::DiagnosticOnUnimplemented => {
97 "only `Self` and generics of the trait are allowed as a format argument"
98 }
99 Self::DiagnosticOnConst => {
100 "only `Self` and generics of the implementation are allowed as a format argument"
101 }
102 Self::DiagnosticOnMove => {
103 "only `This`, `Self` and generics of the type are allowed as a format argument"
104 }
105 Self::DiagnosticOnUnknown => {
106 "only `This` is allowed as a format argument, referring to the failed import"
107 }
108 Self::DiagnosticOnUnmatchArgs => {
109 "only `This` is allowed as a format argument, referring to the macro's name"
110 }
111 }
112 }
113}
114
115fn merge_directives(
116 cx: &mut AcceptContext<'_, '_>,
117 first: &mut Option<(Span, Directive)>,
118 later: (Span, Directive),
119) {
120 if let Some((_, first)) = first {
121 if first.is_rustc_attr || later.1.is_rustc_attr {
122 cx.emit_err(DupesNotAllowed);
123 }
124
125 merge(cx, &mut first.message, later.1.message, sym::message);
126 merge(cx, &mut first.label, later.1.label, sym::label);
127 first.notes.extend(later.1.notes);
128 } else {
129 *first = Some(later);
130 }
131}
132
133fn merge<T>(
134 cx: &mut AcceptContext<'_, '_>,
135 first: &mut Option<(Span, T)>,
136 later: Option<(Span, T)>,
137 option_name: Symbol,
138) {
139 match (first, later) {
140 (Some(_) | None, None) => {}
141 (Some((first_span, _)), Some((later_span, _))) => {
142 let first_span = *first_span;
143 cx.emit_lint(
144 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
145 move |dcx, level| {
146 IgnoredDiagnosticOption { first_span, later_span, option_name }
147 .into_diag(dcx, level)
148 },
149 later_span,
150 );
151 }
152 (first @ None, Some(later)) => {
153 first.get_or_insert(later);
154 }
155 }
156}
157
158fn parse_list<'p>(
159 cx: &mut AcceptContext<'_, '_>,
160 args: &'p ArgParser,
161 mode: Mode,
162) -> Option<&'p MetaItemListParser> {
163 let span = cx.attr_span;
164 match args {
165 ArgParser::List(items) if items.len() != 0 => return Some(items),
166 ArgParser::List(list) => {
167 cx.emit_lint(
171 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
172 move |dcx, level| NonMetaItemDiagnosticAttribute.into_diag(dcx, level),
173 list.span,
174 );
175 }
176 ArgParser::NoArgs => {
177 cx.emit_lint(
178 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
179 move |dcx, level| {
180 MissingOptionsForDiagnosticAttribute {
181 attribute: mode.as_str(),
182 options: mode.expected_options(),
183 }
184 .into_diag(dcx, level)
185 },
186 span,
187 );
188 }
189 ArgParser::NameValue(_) => {
190 cx.emit_lint(
191 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
192 move |dcx, level| {
193 MalFormedDiagnosticAttributeLint {
194 attribute: mode.as_str(),
195 options: mode.allowed_options(),
196 span,
197 }
198 .into_diag(dcx, level)
199 },
200 span,
201 );
202 }
203 }
204 None
205}
206
207fn parse_directive_items<'p>(
208 cx: &mut AcceptContext<'_, '_>,
209 mode: Mode,
210 items: impl Iterator<Item = &'p MetaItemOrLitParser>,
211 is_root: bool,
212) -> Option<Directive> {
213 let condition = None;
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 subcommands = 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 move |dcx, level| {
227 MalFormedDiagnosticAttributeLint {
228 attribute: mode.as_str(),
229 options: mode.allowed_options(),
230 span,
231 }
232 .into_diag(dcx, level)
233 },
234 span,
235 );
236 continue;
237 }}
238
239 macro or_malformed($($code:tt)*) {{
240 let Some(ret) = (
241 try {
242 $($code)*
243 }
244 ) else {
245 malformed!()
246 };
247 ret
248 }}
249
250 macro duplicate($name: ident, $($first_span:tt)*) {{
251 let first_span = $($first_span)*;
252 cx.emit_lint(
253 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
254 move |dcx, level| IgnoredDiagnosticOption {
255 first_span,
256 later_span: span,
257 option_name: $name,
258 }.into_diag(dcx, level),
259 span,
260 );
261 }}
262
263 let item: &MetaItemParser = {
let Some(ret) =
(try {
item.meta_item()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(item.meta_item()?);
264 let name = {
let Some(ret) =
(try {
item.ident()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(item.ident()?).name;
265
266 let value: Option<Ident> = match item.args().as_name_value() {
274 Some(nv) => Some({
let Some(ret) =
(try {
nv.value_as_ident()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(nv.value_as_ident()?)),
275 None => None,
276 };
277
278 let mut parse_format = |input: Ident| {
279 let snippet = cx.sess.source_map().span_to_snippet(input.span).ok();
280 let is_snippet = snippet.is_some();
281 match parse_format_string(input.name, snippet, input.span, mode) {
282 Ok((f, warnings)) => {
283 for warning in warnings {
284 let (FormatWarning::InvalidSpecifier { span }
285 | FormatWarning::PositionalArgument { span }
286 | FormatWarning::IndexedArgument { span }
287 | FormatWarning::DisallowedPlaceholder { span, .. }) = warning;
288 cx.emit_lint(
289 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
290 move |dcx, level| warning.into_diag(dcx, level),
291 span,
292 );
293 }
294
295 f
296 }
297 Err(e) => {
298 cx.emit_lint(
299 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
300 move |dcx, level| {
301 WrappedParserError {
302 description: &e.description,
303 label: &e.label,
304 span: slice_span(input.span, e.span.clone(), is_snippet),
305 }
306 .into_diag(dcx, level)
307 },
308 input.span,
309 );
310 FormatString {
312 input: input.name,
313 span: input.span,
314 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)],
315 }
316 }
317 }
318 };
319 match (mode, name) {
320 (_, sym::message) => {
321 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(value?);
322 if let Some(message) = &message {
323 {
let first_span = message.0;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}.into_diag(dcx, level), span);
}duplicate!(name, message.0)
324 } else {
325 message = Some((item.span(), parse_format(value)));
326 }
327 }
328 (_, sym::label) => {
329 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(value?);
330 if let Some(label) = &label {
331 {
let first_span = label.0;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}.into_diag(dcx, level), span);
}duplicate!(name, label.0)
332 } else {
333 label = Some((item.span(), parse_format(value)));
334 }
335 }
336 (_, sym::note) => {
337 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(value?);
338 notes.push(parse_format(value))
339 }
340 (Mode::RustcOnUnimplemented, sym::parent_label) => {
341 let value = {
let Some(ret) =
(try {
value?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(value?);
342 if parent_label.is_none() {
343 parent_label = Some(parse_format(value));
344 } else {
345 {
let first_span = span;
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
IgnoredDiagnosticOption {
first_span,
later_span: span,
option_name: name,
}.into_diag(dcx, level), span);
}duplicate!(name, span)
346 }
347 }
348 (Mode::RustcOnUnimplemented, sym::on) => {
349 if is_root {
350 let items = {
let Some(ret) =
(try {
item.args().as_list()?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(item.args().as_list()?);
351 let mut iter = items.mixed();
352 let condition: &MetaItemOrLitParser = match iter.next() {
353 Some(c) => c,
354 None => {
355 cx.emit_err(InvalidOnClause::Empty { span });
356 continue;
357 }
358 };
359
360 let condition = parse_condition(condition);
361
362 if items.len() < 2 {
363 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
};malformed!();
366 }
367
368 let mut directive =
369 {
let Some(ret) =
(try {
parse_directive_items(cx, mode, iter, false)?
}) else {
{
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
}
};
ret
}or_malformed!(parse_directive_items(cx, mode, iter, false)?);
370
371 match condition {
372 Ok(c) => {
373 directive.condition = Some(c);
374 subcommands.push(directive);
375 }
376 Err(e) => {
377 cx.emit_err(e);
378 }
379 }
380 } else {
381 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
};malformed!();
382 }
383 }
384
385 _other => {
386 {
cx.emit_lint(MALFORMED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level|
{
MalFormedDiagnosticAttributeLint {
attribute: mode.as_str(),
options: mode.allowed_options(),
span,
}.into_diag(dcx, level)
}, span);
continue;
};malformed!();
387 }
388 }
389 }
390
391 Some(Directive {
392 is_rustc_attr: #[allow(non_exhaustive_omitted_patterns)] match mode {
Mode::RustcOnUnimplemented => true,
_ => false,
}matches!(mode, Mode::RustcOnUnimplemented),
393 condition,
394 subcommands,
395 message,
396 label,
397 notes,
398 parent_label,
399 })
400}
401
402pub(crate) fn parse_format_string(
403 input: Symbol,
404 snippet: Option<String>,
405 span: Span,
406 mode: Mode,
407) -> Result<(FormatString, Vec<FormatWarning>), ParseError> {
408 let s = input.as_str();
409 let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
410 let pieces: Vec<_> = parser.by_ref().collect();
411
412 if let Some(err) = parser.errors.into_iter().next() {
413 return Err(err);
414 }
415 let mut warnings = Vec::new();
416
417 let pieces = pieces
418 .into_iter()
419 .map(|piece| match piece {
420 RpfPiece::Lit(lit) => Piece::Lit(Symbol::intern(lit)),
421 RpfPiece::NextArgument(arg) => {
422 warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal);
423 let arg = parse_arg(&arg, mode, &mut warnings, span, parser.is_source_literal);
424 Piece::Arg(arg)
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 match arg.position {
442 Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
444 (Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext,
445
446 (Mode::RustcOnUnimplemented, sym::Trait) => FormatArg::Trait,
450
451 (
457 Mode::RustcOnUnimplemented
458 | Mode::DiagnosticOnUnknown
459 | Mode::DiagnosticOnMove
460 | Mode::DiagnosticOnUnmatchArgs,
461 sym::This,
462 ) => FormatArg::This,
463
464 (
470 Mode::RustcOnUnimplemented
471 | Mode::DiagnosticOnUnimplemented
472 | Mode::DiagnosticOnMove
473 | Mode::DiagnosticOnConst,
474 kw::SelfUpper,
475 ) => FormatArg::SelfUpper,
476
477 (
483 Mode::RustcOnUnimplemented
484 | Mode::DiagnosticOnUnimplemented
485 | Mode::DiagnosticOnMove
486 | Mode::DiagnosticOnConst,
487 generic_param,
488 ) => FormatArg::GenericParam { generic_param, span },
489
490 (Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchArgs, as_is) => {
492 warnings.push(FormatWarning::DisallowedPlaceholder {
493 span,
494 attr: mode.as_str(),
495 allowed: mode.allowed_format_arguments(),
496 });
497 return FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", as_is))
})format!("{{{as_is}}}")));
498 }
499 },
500
501 Position::ArgumentIs(idx) => {
503 warnings.push(FormatWarning::IndexedArgument { span });
504 FormatArg::AsIs(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}")))
505 }
506 Position::ArgumentImplicitlyIs(_) => {
507 warnings.push(FormatWarning::PositionalArgument { span });
508 FormatArg::AsIs(sym::empty_braces)
509 }
510 }
511}
512
513fn warn_on_format_spec(
516 spec: &FormatSpec<'_>,
517 warnings: &mut Vec<FormatWarning>,
518 input_span: Span,
519 is_source_literal: bool,
520) {
521 if spec.ty != "" {
522 let span = spec
523 .ty_span
524 .as_ref()
525 .map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
526 .unwrap_or(input_span);
527 warnings.push(FormatWarning::InvalidSpecifier { span })
528 }
529}
530
531fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
532 if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
533}
534
535pub(crate) fn parse_condition(
536 input: &MetaItemOrLitParser,
537) -> Result<OnUnimplementedCondition, InvalidOnClause> {
538 let span = input.span();
539 let pred = parse_predicate(input)?;
540 Ok(OnUnimplementedCondition { span, pred })
541}
542
543fn parse_predicate(input: &MetaItemOrLitParser) -> Result<Predicate, InvalidOnClause> {
544 let Some(meta_item) = input.meta_item() else {
545 return Err(InvalidOnClause::UnsupportedLiteral { span: input.span() });
546 };
547
548 let Some(predicate) = meta_item.ident() else {
549 return Err(InvalidOnClause::ExpectedIdentifier {
550 span: meta_item.path().span(),
551 path: meta_item.path().get_attribute_path(),
552 });
553 };
554
555 match meta_item.args() {
556 ArgParser::List(mis) => match predicate.name {
557 sym::any => Ok(Predicate::Any(parse_predicate_sequence(mis)?)),
558 sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)),
559 sym::not => {
560 if let Some(single) = mis.as_single() {
561 Ok(Predicate::Not(Box::new(parse_predicate(single)?)))
562 } else {
563 Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span })
564 }
565 }
566 invalid_pred => {
567 Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred })
568 }
569 },
570 ArgParser::NameValue(p) => {
571 let Some(value) = p.value_as_ident() else {
572 return Err(InvalidOnClause::UnsupportedLiteral { span: p.args_span() });
573 };
574 let name = parse_name(predicate.name);
575 let value = parse_filter(value.name);
576 let kv = NameValue { name, value };
577 Ok(Predicate::Match(kv))
578 }
579 ArgParser::NoArgs => {
580 let flag = parse_flag(predicate)?;
581 Ok(Predicate::Flag(flag))
582 }
583 }
584}
585
586fn parse_predicate_sequence(
587 sequence: &MetaItemListParser,
588) -> Result<ThinVec<Predicate>, InvalidOnClause> {
589 sequence.mixed().map(parse_predicate).collect()
590}
591
592fn parse_flag(Ident { name, span }: Ident) -> Result<Flag, InvalidOnClause> {
593 match name {
594 sym::crate_local => Ok(Flag::CrateLocal),
595 sym::direct => Ok(Flag::Direct),
596 sym::from_desugaring => Ok(Flag::FromDesugaring),
597 invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }),
598 }
599}
600
601fn parse_name(name: Symbol) -> Name {
602 match name {
603 kw::SelfUpper => Name::SelfUpper,
604 sym::from_desugaring => Name::FromDesugaring,
605 sym::cause => Name::Cause,
606 generic => Name::GenericArg(generic),
607 }
608}
609
610fn parse_filter(input: Symbol) -> FilterFormatString {
611 let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
612 .map(|p| match p {
613 RpfPiece::Lit(s) => LitOrArg::Lit(Symbol::intern(s)),
614 RpfPiece::NextArgument(a) => match a.position {
616 Position::ArgumentNamed(
624 arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
625 ) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", arg))
})format!("{{{arg}}}"))),
626
627 Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
628 Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
629 Position::ArgumentIs(idx) => LitOrArg::Lit(Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", idx))
})format!("{{{idx}}}"))),
630 },
631 })
632 .collect();
633 FilterFormatString { pieces }
634}
635
636#[derive(const _: () =
{
impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for
InvalidOnClause where G: rustc_errors::EmissionGuarantee {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess, G> {
match self {
InvalidOnClause::Empty { span: __binding_0 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("empty `on`-clause in `#[rustc_on_unimplemented]`")));
diag.code(E0232);
;
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("empty `on`-clause here")));
diag
}
InvalidOnClause::ExpectedOnePredInNot { span: __binding_0 }
=> {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected a single predicate in `not(..)`")));
diag.code(E0232);
;
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unexpected quantity of predicates here")));
diag
}
InvalidOnClause::UnsupportedLiteral { span: __binding_0 } =>
{
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("literals inside `on`-clauses are not supported")));
diag.code(E0232);
;
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unexpected literal here")));
diag
}
InvalidOnClause::ExpectedIdentifier {
span: __binding_0, path: __binding_1 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected an identifier inside this `on`-clause")));
diag.code(E0232);
;
diag.arg("path", __binding_1);
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected an identifier here, not `{$path}`")));
diag
}
InvalidOnClause::InvalidPredicate {
span: __binding_0, invalid_pred: __binding_1 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this predicate is invalid")));
diag.code(E0232);
;
diag.arg("invalid_pred", __binding_1);
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected one of `any`, `all` or `not` here, not `{$invalid_pred}`")));
diag
}
InvalidOnClause::InvalidFlag {
span: __binding_0, invalid_flag: __binding_1 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("invalid flag in `on`-clause")));
diag.code(E0232);
;
diag.arg("invalid_flag", __binding_1);
diag.span(__binding_0);
diag.span_label(__binding_0,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}`")));
diag
}
}
}
}
};Diagnostic)]
637pub(crate) enum InvalidOnClause {
638 #[diag("empty `on`-clause in `#[rustc_on_unimplemented]`", code = E0232)]
639 Empty {
640 #[primary_span]
641 #[label("empty `on`-clause here")]
642 span: Span,
643 },
644 #[diag("expected a single predicate in `not(..)`", code = E0232)]
645 ExpectedOnePredInNot {
646 #[primary_span]
647 #[label("unexpected quantity of predicates here")]
648 span: Span,
649 },
650 #[diag("literals inside `on`-clauses are not supported", code = E0232)]
651 UnsupportedLiteral {
652 #[primary_span]
653 #[label("unexpected literal here")]
654 span: Span,
655 },
656 #[diag("expected an identifier inside this `on`-clause", code = E0232)]
657 ExpectedIdentifier {
658 #[primary_span]
659 #[label("expected an identifier here, not `{$path}`")]
660 span: Span,
661 path: AttrPath,
662 },
663 #[diag("this predicate is invalid", code = E0232)]
664 InvalidPredicate {
665 #[primary_span]
666 #[label("expected one of `any`, `all` or `not` here, not `{$invalid_pred}`")]
667 span: Span,
668 invalid_pred: Symbol,
669 },
670 #[diag("invalid flag in `on`-clause", code = E0232)]
671 InvalidFlag {
672 #[primary_span]
673 #[label(
674 "expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}`"
675 )]
676 span: Span,
677 invalid_flag: Symbol,
678 },
679}
680
681#[derive(const _: () =
{
impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for
DupesNotAllowed where G: rustc_errors::EmissionGuarantee {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess, G> {
match self {
DupesNotAllowed => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported")));
;
diag
}
}
}
}
};Diagnostic)]
682#[diag(
683 "using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported"
684)]
685pub(crate) struct DupesNotAllowed;