From 222a17181a973278ab3188e38b98cace1cceedc7 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:56:45 -0400 Subject: [PATCH 1/3] test rejection of repeated `rustc_on_unimplemented` attributes --- .../on-unimplemented/duplicate-coalescing.rs | 69 +++++++++++ .../duplicate-coalescing.stderr | 116 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 tests/ui/on-unimplemented/duplicate-coalescing.rs create mode 100644 tests/ui/on-unimplemented/duplicate-coalescing.stderr diff --git a/tests/ui/on-unimplemented/duplicate-coalescing.rs b/tests/ui/on-unimplemented/duplicate-coalescing.rs new file mode 100644 index 0000000000000..a175bc5da2848 --- /dev/null +++ b/tests/ui/on-unimplemented/duplicate-coalescing.rs @@ -0,0 +1,69 @@ +// Check how separate `on_unimplemented` attributes combine into one directive. +// +// Filtered directives keep source order and run before the combined root directive. Therefore, +// the first matching filter provides each scalar option, while root options act as fallbacks. +// Notes from every matching filter and every root directive remain in source order. + +//@ dont-require-annotations: NOTE + +#![feature(rustc_attrs)] +#![allow(internal_features)] + +#[rustc_on_unimplemented( + on(invalid, message = "ignored"), + //~^ WARN invalid flag in `on`-clause + on(Self = "i32", message = "i32 filter message", note = "first filter note"), + message = "fallback message", + note = "first root note" +)] +#[rustc_on_unimplemented( + on( + any(Self = "i32", Self = "u32"), + label = "later filter label", + note = "second filter note" + ), + message = "ignored fallback message", + //~^ WARN `message` is ignored due to previous definition of `message` + label = "fallback label", + note = "second root note" +)] +trait Coalesced {} + +fn takes_coalesced(_: impl Coalesced) {} + +#[diagnostic::on_unimplemented(message = "stable message")] +#[rustc_on_unimplemented(label = "internal label")] +trait StableFirst {} + +fn takes_stable_first(_: impl StableFirst) {} + +#[rustc_on_unimplemented(message = "internal message")] +#[diagnostic::on_unimplemented(label = "stable label")] +trait InternalFirst {} + +fn takes_internal_first(_: impl InternalFirst) {} + +fn main() { + takes_coalesced(0_i32); + //~^ ERROR i32 filter message + //~| NOTE later filter label + //~| NOTE first filter note + //~| NOTE second filter note + //~| NOTE first root note + //~| NOTE second root note + + takes_coalesced(0_u32); + //~^ ERROR fallback message + //~| NOTE later filter label + //~| NOTE second filter note + //~| NOTE first root note + //~| NOTE second root note + + takes_stable_first(()); + //~^ ERROR stable message + //~| NOTE internal label + + takes_internal_first(()); + //~^ ERROR internal message + //~| NOTE stable label +} diff --git a/tests/ui/on-unimplemented/duplicate-coalescing.stderr b/tests/ui/on-unimplemented/duplicate-coalescing.stderr new file mode 100644 index 0000000000000..6ee140b3abda8 --- /dev/null +++ b/tests/ui/on-unimplemented/duplicate-coalescing.stderr @@ -0,0 +1,116 @@ +error[E0232]: invalid flag in `on`-clause + --> $DIR/duplicate-coalescing.rs:13:8 + | +LL | on(invalid, message = "ignored"), + | ^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `invalid` + +error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported + +error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: `message` is ignored due to previous definition of `message` + --> $DIR/duplicate-coalescing.rs:25:5 + | +LL | message = "fallback message", + | ---------------------------- `message` is first declared here +... +LL | message = "ignored fallback message", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `message` is later redundantly declared here + | + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0277]: i32 filter message + --> $DIR/duplicate-coalescing.rs:47:21 + | +LL | takes_coalesced(0_i32); + | --------------- ^^^^^ fallback label + | | + | required by a bound introduced by this call + | + = help: the trait `Coalesced` is not implemented for `i32` + = note: first filter note + = note: first root note + = note: second root note +help: this trait has no implementations, consider adding one + --> $DIR/duplicate-coalescing.rs:30:1 + | +LL | trait Coalesced {} + | ^^^^^^^^^^^^^^^ +note: required by a bound in `takes_coalesced` + --> $DIR/duplicate-coalescing.rs:32:28 + | +LL | fn takes_coalesced(_: impl Coalesced) {} + | ^^^^^^^^^ required by this bound in `takes_coalesced` + +error[E0277]: fallback message + --> $DIR/duplicate-coalescing.rs:55:21 + | +LL | takes_coalesced(0_u32); + | --------------- ^^^^^ fallback label + | | + | required by a bound introduced by this call + | + = help: the trait `Coalesced` is not implemented for `u32` + = note: first root note + = note: second root note +help: this trait has no implementations, consider adding one + --> $DIR/duplicate-coalescing.rs:30:1 + | +LL | trait Coalesced {} + | ^^^^^^^^^^^^^^^ +note: required by a bound in `takes_coalesced` + --> $DIR/duplicate-coalescing.rs:32:28 + | +LL | fn takes_coalesced(_: impl Coalesced) {} + | ^^^^^^^^^ required by this bound in `takes_coalesced` + +error[E0277]: stable message + --> $DIR/duplicate-coalescing.rs:62:24 + | +LL | takes_stable_first(()); + | ------------------ ^^ internal label + | | + | required by a bound introduced by this call + | + = help: the trait `StableFirst` is not implemented for `()` +help: this trait has no implementations, consider adding one + --> $DIR/duplicate-coalescing.rs:36:1 + | +LL | trait StableFirst {} + | ^^^^^^^^^^^^^^^^^ +note: required by a bound in `takes_stable_first` + --> $DIR/duplicate-coalescing.rs:38:31 + | +LL | fn takes_stable_first(_: impl StableFirst) {} + | ^^^^^^^^^^^ required by this bound in `takes_stable_first` + +error[E0277]: internal message + --> $DIR/duplicate-coalescing.rs:66:26 + | +LL | takes_internal_first(()); + | -------------------- ^^ stable label + | | + | required by a bound introduced by this call + | + = help: the trait `InternalFirst` is not implemented for `()` +help: this trait has no implementations, consider adding one + --> $DIR/duplicate-coalescing.rs:42:1 + | +LL | trait InternalFirst {} + | ^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `takes_internal_first` + --> $DIR/duplicate-coalescing.rs:44:33 + | +LL | fn takes_internal_first(_: impl InternalFirst) {} + | ^^^^^^^^^^^^^ required by this bound in `takes_internal_first` + +error: aborting due to 8 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0232, E0277. +For more information about an error, try `rustc --explain E0232`. From f97fb470bbb563da27eff238412a234ec918e30f Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:01:47 -0400 Subject: [PATCH 2/3] coalesce repeated `on_unimplemented` attributes --- .../src/attributes/diagnostic/mod.rs | 29 ++++++------- .../rustc_attr_parsing/src/diagnostics.rs | 6 --- .../duplicate-coalescing.stderr | 18 +++----- tests/ui/on-unimplemented/parent-label.rs | 5 ++- tests/ui/on-unimplemented/parent-label.stderr | 42 +++++++------------ 5 files changed, 40 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index a3a15978d2a37..ad74ee6acacb0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -15,9 +15,8 @@ use thin_vec::{ThinVec, thin_vec}; use crate::context::AcceptContext; use crate::diagnostics::{ - DupesNotAllowed, FormatWarning, IgnoredDiagnosticOption, InvalidOnClause, - MalFormedDiagnosticAttributeLint, MissingOptionsForDiagnosticAttribute, - NonMetaItemDiagnosticAttribute, WrappedParserError, + FormatWarning, IgnoredDiagnosticOption, InvalidOnClause, MalFormedDiagnosticAttributeLint, + MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError, }; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser}; @@ -129,13 +128,15 @@ fn merge_directives( later: (Span, Directive), ) { if let Some((_, first)) = first { - if first.is_rustc_attr || later.1.is_rustc_attr { - cx.emit_err(DupesNotAllowed); - } - - merge(cx, &mut first.message, later.1.message, sym::message); - merge(cx, &mut first.label, later.1.label, sym::label); - first.notes.extend(later.1.notes); + let Directive { is_rustc_attr, filters, message, label, notes, .. } = later.1; + + // Evaluation visits every filter before the root directive. Appending filters and notes + // preserves their source order across separate attribute occurrences. + first.is_rustc_attr |= is_rustc_attr; + first.filters.extend(filters); + merge(cx, &mut first.message, message, sym::message); + merge(cx, &mut first.label, label, sym::label); + first.notes.extend(notes); } else { *first = Some(later); } @@ -215,7 +216,7 @@ fn parse_directive_items<'p>( let mut message: Option<(Span, _)> = None; let mut label: Option<(Span, _)> = None; let mut notes = ThinVec::new(); - let mut parent_label = None; + let mut parent_label: Option = None; let mut filters = ThinVec::new(); for item in items { @@ -346,10 +347,10 @@ fn parse_directive_items<'p>( } (Mode::RustcOnUnimplemented, sym::parent_label) => { let value = or_malformed!(value?); - if parent_label.is_none() { - parent_label = Some(parse_format(value)); + if let Some(parent_label) = &parent_label { + duplicate!(name, parent_label.span) } else { - duplicate!(name, span) + parent_label = Some(parse_format(value)); } } (Mode::RustcOnUnimplemented, sym::on) => { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index bd99e370c70e5..f317cbec5dd7c 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -807,12 +807,6 @@ pub(crate) enum InvalidOnClause { }, } -#[derive(Diagnostic)] -#[diag( - "using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported" -)] -pub(crate) struct DupesNotAllowed; - #[derive(Diagnostic)] #[diag("usage of the unsafe `{$attr_path}` attribute")] #[note("{$note}")] diff --git a/tests/ui/on-unimplemented/duplicate-coalescing.stderr b/tests/ui/on-unimplemented/duplicate-coalescing.stderr index 6ee140b3abda8..a0e65ef4a2090 100644 --- a/tests/ui/on-unimplemented/duplicate-coalescing.stderr +++ b/tests/ui/on-unimplemented/duplicate-coalescing.stderr @@ -4,16 +4,6 @@ error[E0232]: invalid flag in `on`-clause LL | on(invalid, message = "ignored"), | ^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `invalid` -error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported - -error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - warning: `message` is ignored due to previous definition of `message` --> $DIR/duplicate-coalescing.rs:25:5 | @@ -29,12 +19,13 @@ error[E0277]: i32 filter message --> $DIR/duplicate-coalescing.rs:47:21 | LL | takes_coalesced(0_i32); - | --------------- ^^^^^ fallback label + | --------------- ^^^^^ later filter label | | | required by a bound introduced by this call | = help: the trait `Coalesced` is not implemented for `i32` = note: first filter note + = note: second filter note = note: first root note = note: second root note help: this trait has no implementations, consider adding one @@ -52,11 +43,12 @@ error[E0277]: fallback message --> $DIR/duplicate-coalescing.rs:55:21 | LL | takes_coalesced(0_u32); - | --------------- ^^^^^ fallback label + | --------------- ^^^^^ later filter label | | | required by a bound introduced by this call | = help: the trait `Coalesced` is not implemented for `u32` + = note: second filter note = note: first root note = note: second root note help: this trait has no implementations, consider adding one @@ -110,7 +102,7 @@ note: required by a bound in `takes_internal_first` LL | fn takes_internal_first(_: impl InternalFirst) {} | ^^^^^^^^^^^^^ required by this bound in `takes_internal_first` -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0232, E0277. For more information about an error, try `rustc --explain E0232`. diff --git a/tests/ui/on-unimplemented/parent-label.rs b/tests/ui/on-unimplemented/parent-label.rs index b65f6496831ea..cd7753b5e5c24 100644 --- a/tests/ui/on-unimplemented/parent-label.rs +++ b/tests/ui/on-unimplemented/parent-label.rs @@ -1,8 +1,11 @@ -// Test scope annotations from `parent_label` parameter +// Test scope annotations from `parent_label`, including when it is in a later attribute. #![feature(rustc_attrs)] +#[rustc_on_unimplemented(label = "unsatisfied trait bound")] #[rustc_on_unimplemented(parent_label = "in this scope")] +#[rustc_on_unimplemented(parent_label = "ignored parent label")] +//~^ WARN `parent_label` is ignored due to previous definition of `parent_label` trait Trait {} struct Foo; diff --git a/tests/ui/on-unimplemented/parent-label.stderr b/tests/ui/on-unimplemented/parent-label.stderr index 1160b24e3255b..2e0f4c7fb8a0d 100644 --- a/tests/ui/on-unimplemented/parent-label.stderr +++ b/tests/ui/on-unimplemented/parent-label.stderr @@ -1,105 +1,95 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/parent-label.rs:14:11 + --> $DIR/parent-label.rs:17:11 | -LL | let x = || { - | -- in this scope LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | help: the trait `Trait` is not implemented for `Foo` - --> $DIR/parent-label.rs:8:1 + --> $DIR/parent-label.rs:11:1 | LL | struct Foo; | ^^^^^^^^^^ help: this trait has no implementations, consider adding one - --> $DIR/parent-label.rs:6:1 + --> $DIR/parent-label.rs:9:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `f` - --> $DIR/parent-label.rs:10:9 + --> $DIR/parent-label.rs:13:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/parent-label.rs:16:15 + --> $DIR/parent-label.rs:19:15 | -LL | let y = || { - | -- in this scope LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | help: the trait `Trait` is not implemented for `Foo` - --> $DIR/parent-label.rs:8:1 + --> $DIR/parent-label.rs:11:1 | LL | struct Foo; | ^^^^^^^^^^ help: this trait has no implementations, consider adding one - --> $DIR/parent-label.rs:6:1 + --> $DIR/parent-label.rs:9:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `f` - --> $DIR/parent-label.rs:10:9 + --> $DIR/parent-label.rs:13:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/parent-label.rs:22:15 + --> $DIR/parent-label.rs:25:15 | -LL | fn main() { - | --------- in this scope -... LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | help: the trait `Trait` is not implemented for `Foo` - --> $DIR/parent-label.rs:8:1 + --> $DIR/parent-label.rs:11:1 | LL | struct Foo; | ^^^^^^^^^^ help: this trait has no implementations, consider adding one - --> $DIR/parent-label.rs:6:1 + --> $DIR/parent-label.rs:9:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `f` - --> $DIR/parent-label.rs:10:9 + --> $DIR/parent-label.rs:13:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/parent-label.rs:26:7 + --> $DIR/parent-label.rs:29:7 | -LL | fn main() { - | --------- in this scope -... LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | help: the trait `Trait` is not implemented for `Foo` - --> $DIR/parent-label.rs:8:1 + --> $DIR/parent-label.rs:11:1 | LL | struct Foo; | ^^^^^^^^^^ help: this trait has no implementations, consider adding one - --> $DIR/parent-label.rs:6:1 + --> $DIR/parent-label.rs:9:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `f` - --> $DIR/parent-label.rs:10:9 + --> $DIR/parent-label.rs:13:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` From 0e36f43b0673e7441b18feb9baf747379a2e92e1 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:38:25 -0400 Subject: [PATCH 3/3] lint malformed `rustc_on_unimplemented` filters --- .../src/attributes/diagnostic/mod.rs | 29 +++- .../rustc_attr_parsing/src/diagnostics.rs | 14 +- .../src/error_codes/E0232.md | 4 +- compiler/rustc_lint_defs/src/builtin.rs | 30 ++++ tests/ui/on-unimplemented/bad-annotation.rs | 25 +-- .../ui/on-unimplemented/bad-annotation.stderr | 147 +++++++++--------- .../duplicate-coalescing.stderr | 9 +- .../feature-gate-on-unimplemented.rs | 7 + .../feature-gate-on-unimplemented.stderr | 14 +- ...formed-diagnostic-filters.lint_deny.stderr | 14 ++ ...formed-diagnostic-filters.lint_warn.stderr | 14 ++ .../malformed-diagnostic-filters.rs | 18 +++ tests/ui/on-unimplemented/parent-label.stderr | 22 ++- 13 files changed, 245 insertions(+), 102 deletions(-) create mode 100644 tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_deny.stderr create mode 100644 tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_warn.stderr create mode 100644 tests/ui/on-unimplemented/malformed-diagnostic-filters.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index ad74ee6acacb0..70cb07361ee5a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -8,7 +8,8 @@ use rustc_parse_format::{ Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, }; use rustc_session::lint::builtin::{ - MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, + MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FILTERS, + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, }; use rustc_span::{Ident, InnerSpan, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -128,7 +129,7 @@ fn merge_directives( later: (Span, Directive), ) { if let Some((_, first)) = first { - let Directive { is_rustc_attr, filters, message, label, notes, .. } = later.1; + let Directive { is_rustc_attr, filters, message, label, notes, parent_label } = later.1; // Evaluation visits every filter before the root directive. Appending filters and notes // preserves their source order across separate attribute occurrences. @@ -137,6 +138,22 @@ fn merge_directives( merge(cx, &mut first.message, message, sym::message); merge(cx, &mut first.label, label, sym::label); first.notes.extend(notes); + + if let Some(parent_label) = parent_label { + if let Some(first_parent_label) = &first.parent_label { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + IgnoredDiagnosticOption { + first_span: first_parent_label.span, + later_span: parent_label.span, + option_name: sym::parent_label, + }, + parent_label.span, + ); + } else { + first.parent_label = Some(parent_label); + } + } } else { *first = Some(later); } @@ -360,7 +377,11 @@ fn parse_directive_items<'p>( let filter = if let Some(c) = iter.next() { c } else { - cx.emit_err(InvalidOnClause::Empty { span }); + cx.emit_lint( + MALFORMED_DIAGNOSTIC_FILTERS, + InvalidOnClause::Empty { span }, + span, + ); continue; }; @@ -379,7 +400,7 @@ fn parse_directive_items<'p>( filters.push((filter, directive)); } Err(e) => { - cx.emit_err(e); + cx.emit_lint(MALFORMED_DIAGNOSTIC_FILTERS, e, span); } } } else { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index f317cbec5dd7c..dda8b9913afc4 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Applicability, DiagArgValue, E0232, E0264, MultiSpan}; +use rustc_errors::{Applicability, DiagArgValue, E0264, MultiSpan}; use rustc_hir::AttrPath; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -764,39 +764,39 @@ pub(crate) mod unexpected_cfg_value { #[derive(Diagnostic)] pub(crate) enum InvalidOnClause { - #[diag("empty `on`-clause in `#[rustc_on_unimplemented]`", code = E0232)] + #[diag("empty `on`-clause in `#[rustc_on_unimplemented]`")] Empty { #[primary_span] #[label("empty `on`-clause here")] span: Span, }, - #[diag("expected a single predicate in `not(..)`", code = E0232)] + #[diag("expected a single predicate in `not(..)`")] ExpectedOnePredInNot { #[primary_span] #[label("unexpected quantity of predicates here")] span: Span, }, - #[diag("literals inside `on`-clauses are not supported", code = E0232)] + #[diag("literals inside `on`-clauses are not supported")] UnsupportedLiteral { #[primary_span] #[label("unexpected literal here")] span: Span, }, - #[diag("expected an identifier inside this `on`-clause", code = E0232)] + #[diag("expected an identifier inside this `on`-clause")] ExpectedIdentifier { #[primary_span] #[label("expected an identifier here, not `{$path}`")] span: Span, path: AttrPath, }, - #[diag("this predicate is invalid", code = E0232)] + #[diag("this predicate is invalid")] InvalidPredicate { #[primary_span] #[label("expected one of `any`, `all` or `not` here, not `{$invalid_pred}`")] span: Span, invalid_pred: Symbol, }, - #[diag("invalid flag in `on`-clause", code = E0232)] + #[diag("invalid flag in `on`-clause")] InvalidFlag { #[primary_span] #[label( diff --git a/compiler/rustc_error_codes/src/error_codes/E0232.md b/compiler/rustc_error_codes/src/error_codes/E0232.md index cb0797006092a..57995e56f2dc9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0232.md +++ b/compiler/rustc_error_codes/src/error_codes/E0232.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + The `#[rustc_on_unimplemented]` attribute lets you specify a custom error message for when a particular trait isn't implemented on a type placed in a position that needs that trait. The attribute will let you filter on various types, with `on`: -```compile_fail,E0232 +```ignore (error is no longer emitted) #![feature(rustc_attrs)] #![allow(internal_features)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2d9d7f337e004..cc5a1f84def27 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -69,6 +69,7 @@ pub mod hardwired { MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, MACRO_USE_EXTERN_CRATE, MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_FILTERS, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, META_VARIABLE_MISUSE, METHOD_CALL_ON_DIVERGING_INFER_VAR, @@ -4542,6 +4543,35 @@ declare_lint! { "detects diagnostic attribute with malformed diagnostic format literals", } +declare_lint! { + /// The `malformed_diagnostic_filters` lint detects malformed filters in diagnostic + /// attributes. + /// + /// ### Example + /// + // FIXME(bootstrap): Use a regular Rust doc code block after stage 0 emits + // `malformed_diagnostic_filters` instead of E0232 for this example. + #[cfg_attr(bootstrap, doc = "```rust,ignore (stage 0 emits E0232)")] + #[cfg_attr(not(bootstrap), doc = "```rust")] + /// #![feature(rustc_attrs)] + /// #![allow(internal_features)] + /// + /// #[rustc_on_unimplemented(on(invalid, message = "unused"))] + /// trait Trait {} + #[doc = "```"] + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A `rustc_on_unimplemented` filter must use a supported flag, a name-value predicate, + /// or the `all`, `any`, and `not` predicate operators. Invalid filters are ignored. + pub MALFORMED_DIAGNOSTIC_FILTERS, + Warn, + "detects malformed filters in diagnostic attributes", + @feature_gate = rustc_attrs; +} + declare_lint! { /// The `ambiguous_glob_imports` lint detects glob imports that should report ambiguity /// errors, but previously didn't do that due to rustc bugs. diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 7fec70df3a73c..ce04f175f87b6 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -1,3 +1,7 @@ +// Check that every malformed `on` filter warns without stopping compilation. + +//@ check-pass + #![crate_type = "lib"] #![feature(rustc_attrs)] #![allow(unused)] @@ -44,12 +48,13 @@ trait Invalid {} trait DuplicateMessage {} #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] -//~^ ERROR invalid flag in `on`-clause +//~^ WARN invalid flag in `on`-clause //~| NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `desugared` +//~| NOTE `#[warn(malformed_diagnostic_filters)]` on by default trait OnInWrongPosition {} #[rustc_on_unimplemented(on(), message = "y")] -//~^ ERROR empty `on`-clause +//~^ WARN empty `on`-clause //~^^ NOTE empty `on`-clause here trait EmptyOn {} @@ -69,42 +74,42 @@ trait OnWithoutDirectives {} trait NestedOn {} #[rustc_on_unimplemented(on("y", message = "y"))] -//~^ ERROR literals inside `on`-clauses are not supported +//~^ WARN literals inside `on`-clauses are not supported //~^^ NOTE unexpected literal here trait UnsupportedLiteral {} #[rustc_on_unimplemented(on(42, message = "y"))] -//~^ ERROR literals inside `on`-clauses are not supported +//~^ WARN literals inside `on`-clauses are not supported //~^^ NOTE unexpected literal here trait UnsupportedLiteral2 {} #[rustc_on_unimplemented(on(not(a, b), message = "y"))] -//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^ WARN expected a single predicate in `not(..)` //~^^ NOTE unexpected quantity of predicates here trait ExpectedOnePattern {} #[rustc_on_unimplemented(on(not(), message = "y"))] -//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^ WARN expected a single predicate in `not(..)` //~^^ NOTE unexpected quantity of predicates here trait ExpectedOnePattern2 {} #[rustc_on_unimplemented(on(thing::What, message = "y"))] -//~^ ERROR expected an identifier inside this `on`-clause +//~^ WARN expected an identifier inside this `on`-clause //~^^ NOTE expected an identifier here, not `thing::What` trait KeyMustBeIdentifier {} #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] -//~^ ERROR expected an identifier inside this `on`-clause +//~^ WARN expected an identifier inside this `on`-clause //~^^ NOTE expected an identifier here, not `thing::What` trait KeyMustBeIdentifier2 {} #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] -//~^ ERROR this predicate is invalid +//~^ WARN this predicate is invalid //~^^ NOTE expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` trait InvalidPredicate {} #[rustc_on_unimplemented(on(something, message = "y"))] -//~^ ERROR invalid flag in `on`-clause +//~^ WARN invalid flag in `on`-clause //~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` trait InvalidFlag {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 88666f359719b..b26ec5bbaeb53 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -1,65 +1,5 @@ -error[E0232]: invalid flag in `on`-clause - --> $DIR/bad-annotation.rs:46:44 - | -LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] - | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `desugared` - -error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:51:26 - | -LL | #[rustc_on_unimplemented(on(), message = "y")] - | ^^^^ empty `on`-clause here - -error[E0232]: literals inside `on`-clauses are not supported - --> $DIR/bad-annotation.rs:71:29 - | -LL | #[rustc_on_unimplemented(on("y", message = "y"))] - | ^^^ unexpected literal here - -error[E0232]: literals inside `on`-clauses are not supported - --> $DIR/bad-annotation.rs:76:29 - | -LL | #[rustc_on_unimplemented(on(42, message = "y"))] - | ^^ unexpected literal here - -error[E0232]: expected a single predicate in `not(..)` - --> $DIR/bad-annotation.rs:81:32 - | -LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] - | ^^^^^^ unexpected quantity of predicates here - -error[E0232]: expected a single predicate in `not(..)` - --> $DIR/bad-annotation.rs:86:32 - | -LL | #[rustc_on_unimplemented(on(not(), message = "y"))] - | ^^ unexpected quantity of predicates here - -error[E0232]: expected an identifier inside this `on`-clause - --> $DIR/bad-annotation.rs:91:29 - | -LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] - | ^^^^^^^^^^^ expected an identifier here, not `thing::What` - -error[E0232]: expected an identifier inside this `on`-clause - --> $DIR/bad-annotation.rs:96:29 - | -LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] - | ^^^^^^^^^^^ expected an identifier here, not `thing::What` - -error[E0232]: this predicate is invalid - --> $DIR/bad-annotation.rs:101:29 - | -LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] - | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` - -error[E0232]: invalid flag in `on`-clause - --> $DIR/bad-annotation.rs:106:29 - | -LL | #[rustc_on_unimplemented(on(something, message = "y"))] - | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` - warning: there is no parameter `C` on trait `ParameterNotPresent` - --> $DIR/bad-annotation.rs:20:90 + --> $DIR/bad-annotation.rs:24:90 | LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{C}>`")] | ^ @@ -67,19 +7,19 @@ LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with para = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: there is no parameter `_Self` on trait `InvalidName` - --> $DIR/bad-annotation.rs:111:29 + --> $DIR/bad-annotation.rs:116:29 | LL | #[rustc_on_unimplemented(on(_Self = "y", message = "y"))] | ^^^^^^^^^^^ warning: there is no parameter `abc` on trait `InvalidName2` - --> $DIR/bad-annotation.rs:115:29 + --> $DIR/bad-annotation.rs:120:29 | LL | #[rustc_on_unimplemented(on(abc = "y", message = "y"))] | ^^^^^^^^^ warning: missing options for `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:15:1 + --> $DIR/bad-annotation.rs:19:1 | LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +28,7 @@ LL | #[rustc_on_unimplemented] = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: positional arguments are not permitted in diagnostic attributes - --> $DIR/bad-annotation.rs:25:90 + --> $DIR/bad-annotation.rs:29:90 | LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{}>`")] | ^ remove this format argument @@ -96,7 +36,7 @@ LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with para = help: you can print empty braces by escaping them warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:30:26 + --> $DIR/bad-annotation.rs:34:26 | LL | #[rustc_on_unimplemented(lorem = "")] | ^^^^^^^^^^ invalid option found here @@ -104,7 +44,7 @@ LL | #[rustc_on_unimplemented(lorem = "")] = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:35:26 + --> $DIR/bad-annotation.rs:39:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -112,23 +52,37 @@ LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] = help: see warning: `message` is ignored due to previous definition of `message` - --> $DIR/bad-annotation.rs:40:41 + --> $DIR/bad-annotation.rs:44:41 | LL | #[rustc_on_unimplemented(message = "x", message = "y")] | ------------- ^^^^^^^^^^^^^ `message` is later redundantly declared here | | | `message` is first declared here -warning: malformed `rustc_on_unimplemented` attribute +warning: invalid flag in `on`-clause + --> $DIR/bad-annotation.rs:50:44 + | +LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] + | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `desugared` + | + = note: `#[warn(malformed_diagnostic_filters)]` on by default + +warning: empty `on`-clause in `#[rustc_on_unimplemented]` --> $DIR/bad-annotation.rs:56:26 | +LL | #[rustc_on_unimplemented(on(), message = "y")] + | ^^^^ empty `on`-clause here + +warning: malformed `rustc_on_unimplemented` attribute + --> $DIR/bad-annotation.rs:61:26 + | LL | #[rustc_on_unimplemented(on = "x", message = "y")] | ^^^^^^^^ invalid option found here | = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:61:26 + --> $DIR/bad-annotation.rs:66:26 | LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")] | ^^^^^^^^^^^^^^ invalid option found here @@ -136,13 +90,60 @@ LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")] = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:66:46 + --> $DIR/bad-annotation.rs:71:46 | LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | = help: see -error: aborting due to 10 previous errors; 11 warnings emitted +warning: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:76:29 + | +LL | #[rustc_on_unimplemented(on("y", message = "y"))] + | ^^^ unexpected literal here + +warning: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:81:29 + | +LL | #[rustc_on_unimplemented(on(42, message = "y"))] + | ^^ unexpected literal here + +warning: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:86:32 + | +LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] + | ^^^^^^ unexpected quantity of predicates here + +warning: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:91:32 + | +LL | #[rustc_on_unimplemented(on(not(), message = "y"))] + | ^^ unexpected quantity of predicates here + +warning: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:96:29 + | +LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +warning: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:101:29 + | +LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +warning: this predicate is invalid + --> $DIR/bad-annotation.rs:106:29 + | +LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] + | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` + +warning: invalid flag in `on`-clause + --> $DIR/bad-annotation.rs:111:29 + | +LL | #[rustc_on_unimplemented(on(something, message = "y"))] + | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` + +warning: 21 warnings emitted -For more information about this error, try `rustc --explain E0232`. diff --git a/tests/ui/on-unimplemented/duplicate-coalescing.stderr b/tests/ui/on-unimplemented/duplicate-coalescing.stderr index a0e65ef4a2090..69e35a18fdf7e 100644 --- a/tests/ui/on-unimplemented/duplicate-coalescing.stderr +++ b/tests/ui/on-unimplemented/duplicate-coalescing.stderr @@ -1,8 +1,10 @@ -error[E0232]: invalid flag in `on`-clause +warning: invalid flag in `on`-clause --> $DIR/duplicate-coalescing.rs:13:8 | LL | on(invalid, message = "ignored"), | ^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `invalid` + | + = note: `#[warn(malformed_diagnostic_filters)]` on by default warning: `message` is ignored due to previous definition of `message` --> $DIR/duplicate-coalescing.rs:25:5 @@ -102,7 +104,6 @@ note: required by a bound in `takes_internal_first` LL | fn takes_internal_first(_: impl InternalFirst) {} | ^^^^^^^^^^^^^ required by this bound in `takes_internal_first` -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0232, E0277. -For more information about an error, try `rustc --explain E0232`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs index 6bb7ab0d1a56b..56adc357bffeb 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs @@ -1,7 +1,14 @@ // Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate. +#![allow(malformed_diagnostic_filters)] +//~^ WARN unknown lint: `malformed_diagnostic_filters` +//~| NOTE the `malformed_diagnostic_filters` lint is unstable +//~| HELP add `#![feature(rustc_attrs)]` to the crate attributes to enable +//~| NOTE `#[warn(unknown_lints)]` on by default + #[rustc_on_unimplemented(label = "test error `{Self}` with `{Bar}`")] //~^ ERROR use of an internal attribute [E0658] +//~| HELP add `#![feature(rustc_attrs)]` to the crate attributes to enable //~| NOTE the `rustc_on_unimplemented` attribute is an internal implementation detail that will never be stable //~| NOTE see the `diagnostic::on_unimplemented` attribute for the stable equivalent of this attribute trait Foo {} diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr index a971398222862..c5a1624747e93 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr @@ -1,5 +1,15 @@ +warning: unknown lint: `malformed_diagnostic_filters` + --> $DIR/feature-gate-on-unimplemented.rs:3:10 + | +LL | #![allow(malformed_diagnostic_filters)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `malformed_diagnostic_filters` lint is unstable + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: `#[warn(unknown_lints)]` on by default + error[E0658]: use of an internal attribute - --> $DIR/feature-gate-on-unimplemented.rs:3:3 + --> $DIR/feature-gate-on-unimplemented.rs:9:3 | LL | #[rustc_on_unimplemented(label = "test error `{Self}` with `{Bar}`")] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -8,6 +18,6 @@ LL | #[rustc_on_unimplemented(label = "test error `{Self}` with `{Bar}`")] = note: the `rustc_on_unimplemented` attribute is an internal implementation detail that will never be stable = note: see the `diagnostic::on_unimplemented` attribute for the stable equivalent of this attribute -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_deny.stderr b/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_deny.stderr new file mode 100644 index 0000000000000..a0f302e23b9af --- /dev/null +++ b/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_deny.stderr @@ -0,0 +1,14 @@ +error: invalid flag in `on`-clause + --> $DIR/malformed-diagnostic-filters.rs:13:29 + | +LL | #[rustc_on_unimplemented(on(invalid, message = "unused"), message = "fallback")] + | ^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `invalid` + | +note: the lint level is defined here + --> $DIR/malformed-diagnostic-filters.rs:11:29 + | +LL | #![cfg_attr(lint_deny, deny(malformed_diagnostic_filters))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_warn.stderr b/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_warn.stderr new file mode 100644 index 0000000000000..9282d3ee61a2a --- /dev/null +++ b/tests/ui/on-unimplemented/malformed-diagnostic-filters.lint_warn.stderr @@ -0,0 +1,14 @@ +warning: invalid flag in `on`-clause + --> $DIR/malformed-diagnostic-filters.rs:13:29 + | +LL | #[rustc_on_unimplemented(on(invalid, message = "unused"), message = "fallback")] + | ^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `invalid` + | +note: the lint level is defined here + --> $DIR/malformed-diagnostic-filters.rs:10:29 + | +LL | #![cfg_attr(lint_warn, warn(malformed_diagnostic_filters))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/on-unimplemented/malformed-diagnostic-filters.rs b/tests/ui/on-unimplemented/malformed-diagnostic-filters.rs new file mode 100644 index 0000000000000..e16d52672b5c2 --- /dev/null +++ b/tests/ui/on-unimplemented/malformed-diagnostic-filters.rs @@ -0,0 +1,18 @@ +// Check the lint levels for malformed `rustc_on_unimplemented` filters. + +//@ revisions: lint_allow lint_warn lint_deny +//@[lint_allow] check-pass +//@[lint_warn] check-pass + +#![feature(rustc_attrs)] +#![allow(internal_features)] +#![cfg_attr(lint_allow, allow(malformed_diagnostic_filters))] +#![cfg_attr(lint_warn, warn(malformed_diagnostic_filters))] +#![cfg_attr(lint_deny, deny(malformed_diagnostic_filters))] + +#[rustc_on_unimplemented(on(invalid, message = "unused"), message = "fallback")] +//[lint_warn]~^ WARN invalid flag in `on`-clause +//[lint_deny]~^^ ERROR invalid flag in `on`-clause +trait Trait {} + +fn main() {} diff --git a/tests/ui/on-unimplemented/parent-label.stderr b/tests/ui/on-unimplemented/parent-label.stderr index 2e0f4c7fb8a0d..c140cff98c269 100644 --- a/tests/ui/on-unimplemented/parent-label.stderr +++ b/tests/ui/on-unimplemented/parent-label.stderr @@ -1,6 +1,18 @@ +warning: `parent_label` is ignored due to previous definition of `parent_label` + --> $DIR/parent-label.rs:7:41 + | +LL | #[rustc_on_unimplemented(parent_label = "in this scope")] + | --------------- `parent_label` is first declared here +LL | #[rustc_on_unimplemented(parent_label = "ignored parent label")] + | ^^^^^^^^^^^^^^^^^^^^^^ `parent_label` is later redundantly declared here + | + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/parent-label.rs:17:11 | +LL | let x = || { + | -- in this scope LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | @@ -25,6 +37,8 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/parent-label.rs:19:15 | +LL | let y = || { + | -- in this scope LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | @@ -49,6 +63,9 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/parent-label.rs:25:15 | +LL | fn main() { + | --------- in this scope +... LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | @@ -73,6 +90,9 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/parent-label.rs:29:7 | +LL | fn main() { + | --------- in this scope +... LL | f(Foo {}); | - ^^^^^^ unsatisfied trait bound | | @@ -94,6 +114,6 @@ note: required by a bound in `f` LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`.