This code compiles:
struct B(u32)
#[derive(Clone)]
struct A<'a>(&'a B)
impl <'a> Copy for A<'a> {}
But this one does not:
#[derive(Clone)]
struct A<'a, T>(&'a T)
impl <'a, T> Copy for A<'a, T> {}
Compiler error: the trait Clone is not implemented for T
I suppose this is a bug in the Clone macro. Should I fill a bug report?
This is the expected behavior. The implementation produced by #[derive(Clone)] has bounds requiring every generic parameter to implement Clone. You’ll need to manually implement Clone for this type.
From the docs:
For a generic struct, #[derive] implements Clone conditionally by adding bound Clone on generic parameters.
Changing the way this works might be a good idea, except that it has the potential to break exising code that relies on the current behavior.
Trick:
type A<'a, T> = A_<&'a T>;
#[derive(Clone)]
struct A_<Ref>(Ref);
impl<T> Copy for A<'_, T> {}
The more general and less hacky alternative (but which, when dealing with #[derive(Eq)], does not yield the "structural equality" property required for that type to be used as constant patterns to match against), is to use a derive that is more tweakable than the one in the standard library, such as ::derivative's:
#[derive(::derivative::Derivative)]
#[derivative(Clone(bound = ""))]
struct A<'a, T>(&'a T);
impl<T> Copy for A<'_, T> {}
As others have mentioned, this is a part of the way #[derive(Clone)] was designed. The playground actually has an "expand macros" feature which will show you the code generated by our derive macro.
In this case, I got the following:
struct A<'a, T>(&'a T);
#[automatically_derived]
#[allow(unused_qualifications)]
impl <'a, T: Clone> Clone for A<'a, T> {
#[inline]
fn clone(&self) -> A<'a, T> {
match *self {
A(ref __self_0_0) =>
A(Clone::clone(&(*__self_0_0))),
}
}
}
impl <'a, T> Copy for A<'a, T> { }
(playground)
What the compiler "really" wants to generate is impl<'a, T> Clone for A<'a, T> where &'a T: Clone { ... }, but that would mean we expose the type of A's private fields as part of its public API. This is particularly not great when the field is more interesting than a simple reference.
The current design works for 99% of cases and doesn't need to break privacy, so you are forced to manually implement Clone in that other 1% of cases.