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