Improve error message around unexpected derive bounds
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
use std::sync::Arc;
// Not Clone
struct Foo;
#[derive(Clone)]
struct Bar<T>(Arc<T>);
fn main() {
let x = Bar(Arc::new(Foo));
x.clone(); // Error!
}
Current output
error[E0599]: the method `clone` exists for struct `Bar<Foo>`, but its trait bounds were not satisfied
--> src/main.rs:11:7
|
4 | struct Foo;
| ---------- doesn't satisfy `Foo: Clone`
...
7 | struct Bar<T>(Arc<T>);
| ------------- method `clone` not found for this struct because it doesn't satisfy `Bar<Foo>: Clone`
...
11 | x.clone(); // Error!
| ^^^^^ method cannot be called on `Bar<Foo>` due to unsatisfied trait bounds
|
note: trait bound `Foo: Clone` was not satisfied
--> src/main.rs:6:10
|
6 | #[derive(Clone)]
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
help: consider annotating `Foo` with `#[derive(Clone)]`
|
4 + #[derive(Clone)]
5 | struct Foo;
|
For more information about this error, try `rustc --explain E0599`.
Desired output
note: The implementation of Clone provided by #[derive(Clone)] on struct Bar
has a trait bound of "T: Clone". This may be overly restrictive. If the constraint
is incorrect, manually write an implementation of Clone for Bar without this
trait bound. For example:
impl Clone for Bar {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
Rationale and extra context
Its quite surprising to many people that #[derive(Clone)] on a generic struct Foo<T> creates a trait implementation with a bound of T: Clone. Clone is trivially implementable for any type where all the fields implement Clone. The generic parameter itself is irrelevant.
You can - for example - have structs which can trivially be Cloned but where the trait is not clone (as in the example above). Or the inverse - for example, when a field is of type Cell<T> or Mutex<T>.
Currently the error does not sufficiently hint that this is the case. I personally spent half an hour fighting the compiler the first time I ran into it - I was confused how my #[derive(Clone)] was seemingly being ignored. There was a recent blog post about this issue which gathered over 100 comments on HN. Others are clearly running into this problem too.
The error message suggests the problem is with the lack of impl Clone for T. But this is a distraction. The right fix is often to manually implement Clone.
This blog post has some backstory on this choice within derive itself, and talks about how we might fix derive itself such that it doesn't have this pitfall. Unfortunately, doing so may have semver implications.
In the meantime, it'd be great to fix rustc's diagnostic message to at least point people in the right direction.
The diagnostic above should probably be added when all of these conditions are met:
.clone()is called (ordefault(),eq(), etc)- The type does not implement clone
- There is a
#[derive(Clone)]on the type - The type has generic parameters
Other cases
I've used Clone here an example, but the exact same problem shows up with other built in derive macros. For example, PartialEq, Default, Debug and so on.
Ideally, we should improve the diagnostics in all of these cases.
Rust Version
rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the provided Rust example and tracing rustc's diagnostic path for method calls blocked by derive-generated trait bounds. Compare the existing output with the requested Clone and other built-in derive cases; done means the diagnostic explains the restrictive bound and points to a manual implementation without obscuring unrelated errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100