Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, what is the difference between the output in this PR and the output if we remove the following lines? Are there some cases where the note is useful? It'd be a good idea to include that context in the comment or at least in this PR.

on(
all(crate_local, not(Self = "{union}")),
note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`"
),
on(all(crate_local, Self = "{union}"), note = "manually `impl {This} for {Self}`"),

Copy link
Copy Markdown
Contributor Author

@Dnreikronos Dnreikronos May 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good call flagging this. Short version: deleting those lines would kill the note everywhere, but it's only redundant some of the time, so I skip it conditionally instead.

suggest_derive shows consider annotating X with #[derive(..)] only when can_suggest_derive holds: a crate-local ADT, not a union, and all fields already implement the trait. When that fires, the note and the suggestion are saying the same thing, so the note is just clutter (that's what the stderr diffs are trimming).

When can_suggest_derive is false there's no suggestion at all, and then the note is the only nudge the user gets. Easiest case to picture is a local struct with a field that isn't Debug:

struct Inner; // no Debug

struct Outer {
    inner: Inner,
}

fn main() {
    println!("{:?}", Outer { inner: Inner });
}
error[E0277]: `Outer` doesn't implement `Debug`
   = note: add `#[derive(Debug)]` to `Outer` or manually `impl Debug for Outer`

No consider annotating line here, since Outer's field isn't Debug, so dropping the lines outright would leave this one with nothing actionable. Same story when main_trait_predicate != leaf_trait_predicate: the note's built from the main predicate and the suggestion from the leaf, so they don't overlap.

Happy to pull this into the PR description too. Thanks for pushing on it! :)

Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some((msg, span)) = type_def {
err.span_label(span, msg);
}
for note in notes {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(note);
// `#[rustc_on_unimplemented]` notes for derivable traits (e.g. `Debug`'s
// "add `#[derive(Debug)]` to `X` or manually `impl Debug for X`") duplicate
// the `consider annotating X with #[derive(..)]` suggestion that
// `suggest_derive` emits below, so skip them when that suggestion will be
// shown. We keep the note otherwise (e.g. when a field isn't `Debug`, so
// the derive can't be suggested) to avoid leaving the diagnostic without
// actionable guidance.
let derive_suggestion_will_be_shown = main_trait_predicate
== leaf_trait_predicate
&& self.can_suggest_derive(&obligation, leaf_trait_predicate);
if !derive_suggestion_will_be_shown {
for note in notes {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display
// it.
err.note(note);
}
}
if let Some(s) = parent_label {
let body = obligation.cause.body_id;
Expand Down
4 changes: 0 additions & 4 deletions tests/ui/derives/debug/derives-span-Debug.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ LL | #[derive(Debug)]
LL | x: Error,
| ^^^^^^^^ the trait `Debug` is not implemented for `Error`
|
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand All @@ -23,7 +22,6 @@ LL | #[derive(Debug)]
LL | Error,
| ^^^^^ the trait `Debug` is not implemented for `Error`
|
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand All @@ -39,7 +37,6 @@ LL | struct Struct {
LL | x: Error,
| ^^^^^^^^ the trait `Debug` is not implemented for `Error`
|
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand All @@ -55,7 +52,6 @@ LL | struct TupleStruct(
LL | Error,
| ^^^^^ the trait `Debug` is not implemented for `Error`
|
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/derives/redundant-derive-note-on-unimplemented.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Regression test for the redundant `note: add `#[derive(Debug)]` to `X` or manually
// `impl Debug for X`` that was emitted alongside the `consider annotating X with
// `#[derive(Debug)]`` suggestion. When the derive suggestion is shown, the note is
// redundant and should be suppressed.
//
// See https://github.com/rust-lang/rust/issues/157118

#[derive(Debug)]
struct S<T>(T);

struct X;

fn main() {
println!("{:?}", S(X)); //~ ERROR `X` doesn't implement `Debug`
}
31 changes: 31 additions & 0 deletions tests/ui/derives/redundant-derive-note-on-unimplemented.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error[E0277]: `X` doesn't implement `Debug`
--> $DIR/redundant-derive-note-on-unimplemented.rs:14:22
|
LL | println!("{:?}", S(X));
| ---- ^^^^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| |
| required by this formatting parameter
|
= help: the trait `Debug` is not implemented for `X`
help: the trait `Debug` is implemented for `S<T>`
--> $DIR/redundant-derive-note-on-unimplemented.rs:8:10
|
LL | #[derive(Debug)]
| ^^^^^
note: required for `S<X>` to implement `Debug`
--> $DIR/redundant-derive-note-on-unimplemented.rs:9:8
|
LL | #[derive(Debug)]
| ----- in this derive macro expansion
LL | struct S<T>(T);
| ^ - type parameter would need to implement `Debug`
= help: consider manually implementing `Debug` to avoid undesired bounds
help: consider annotating `X` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
LL | struct X;
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
2 changes: 0 additions & 2 deletions tests/ui/fmt/format-args-argument-span.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ LL | println!("{x} {x:?} {x}");
| ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `DisplayOnly`
= note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly`
help: consider annotating `DisplayOnly` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand All @@ -41,7 +40,6 @@ LL | println!("{x} {x:?} {x}", x = DisplayOnly);
| required by this formatting parameter
|
= help: the trait `Debug` is not implemented for `DisplayOnly`
= note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly`
help: consider annotating `DisplayOnly` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/fmt/non-source-literals.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ LL | let _ = format!(concat!("{:", "?}"), NonDebug);
| ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `NonDebug`
= note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug`
help: consider annotating `NonDebug` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand All @@ -45,7 +44,6 @@ LL | let _ = format!(concat!("{", "0", ":?}"), NonDebug);
| ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `NonDebug`
= note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug`
help: consider annotating `NonDebug` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ error[E0277]: `Foo` doesn't implement `Debug`
LL | a.unwrap();
| ^^^^^^ the trait `Debug` is not implemented for `Foo`
|
= note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo`
note: required by a bound in `Result::<T, E>::unwrap`
--> $SRC_DIR/core/src/result.rs:LL:COL
help: consider annotating `Foo` with `#[derive(Debug)]`
Expand Down
1 change: 0 additions & 1 deletion tests/ui/modules/issue-107649.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ error[E0277]: `Dummy` doesn't implement `Debug`
105 | dbg!(lib::Dummy);
| ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy`
|
= note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy`
help: consider annotating `Dummy` with `#[derive(Debug)]`
--> $DIR/auxiliary/dummy_lib.rs:2:1
|
Expand Down
1 change: 0 additions & 1 deletion tests/ui/on-unimplemented/no-debug.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ LL | println!("{:?} {:?}", Foo, Bar);
| required by this formatting parameter
|
= help: the trait `Debug` is not implemented for `Foo`
= note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo`
help: consider annotating `Foo` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ error[E0277]: `NotDebug` doesn't implement `Debug`
LL | let _: NotDebug = dbg!(NotDebug);
| ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug`
|
= note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug`
help: consider annotating `NotDebug` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
1 change: 0 additions & 1 deletion tests/ui/span/issue-71363.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ error[E0277]: `MyError` doesn't implement `Debug`
4 | impl std::error::Error for MyError {}
| ^^^^^^^ the trait `Debug` is not implemented for `MyError`
|
= note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError`
note: required by a bound in `std::error::Error`
--> $SRC_DIR/core/src/error.rs:LL:COL
help: consider annotating `MyError` with `#[derive(Debug)]`
Expand Down
1 change: 0 additions & 1 deletion tests/ui/suggestions/derive-macro-missing-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ LL | #[derive(Debug)]
LL | struct Outer<T>(Inner<T>);
| ^^^^^^^^ the trait `Debug` is not implemented for `a::Inner<T>`
|
= note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
help: consider annotating `a::Inner<T>` with `#[derive(Debug)]`
|
LL + #[derive(Debug)]
Expand Down
Loading