derive(Clone) bug?

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.

1 Like