Is there a way to make a generic type always `Copy`?

I'm working on a custom pointer type, and I'm running into a weird result. I'd like my pointers to be Copy no matter what they point to, but it seems impossible to do with a plain #[derive(Clone, Copy)].

Here's a minimal example:

#[derive(Clone, Copy)]
struct Foo<T>(*const T);

fn bar<T>(foo: &Foo<T>) -> Foo<T> {
    *foo // compile error - move out of non-Copy type
}

I suspect that the cause of this issue is that the derive macro ignores the fact that *const T is always copiable, and so rejects making Foo<T> copiable. Is there a way to make it so that Foo<T> can be Copy?

1 Like

You can always write the impls yourself instead of deriving them:

impl<T> Clone for Foo<T> {
    // ...
}
impl<T> Copy for Foo<T> {}
3 Likes

Thanks! I had somehow deluded myself into thinking that Copy was some sort of compiler magic that could only be done through deriving.

It is magic, but it's a bit different one. You can implement Copy manually for types which only include Copy types while #[derive(Clone, Copy)] adds additional restrictions.

This is important because for Copy type Clone have to do a bitwise copy, nothing else is allowed.

It's all is described in the documentation, though.

1 Like

That's not true. It's bad practice if they don't do exactly the same thing, but the compiler can't enforce this. The documentation you linked to doesn't say that, either – it only says that a manual Clone impl for a Copy type can simply return *self for ease of implementation.

However, an abomination like this still compiles and runs.

2 Likes

Luckily, Clippy tends to catch these kinds of errors:

error: incorrect implementation of `clone` on a `Copy` type
  --> src/main.rs:10:29
   |
10 |       fn clone(&self) -> Self {
   |  _____________________________^
11 | |         Foo {
12 | |             bar: 3.1415927,
13 | |             qux: char::try_from(self.qux as u32 + 1).unwrap(),
14 | |         }
15 | |     }
   | |_____^ help: change this to: `{ *self }`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type
   = note: `#[deny(clippy::incorrect_clone_impl_on_copy_type)]` on by default

Given the common usage of specialization for optimizing .clone() into bitwise copy, in the standard library, I’m a bit surprised to find no stronger wording against such practices in the docs.

1 Like