rustcompiler-errors

"field must implement `Copy`" in union on field with derived Copy


Erring code in question:

#[derive(Debug, Clone, Copy)]
struct OfflineWord {
    word: u64,
    flag: u64,
}

#[derive(Debug, Clone, Copy)]
struct OnlineWord<'file, F: AsRef<Path>> {
    file: &'file F,
    byte_offset: u64,
}

union FileWord<'file, F: AsRef<Path>> {
    online: OnlineWord<'file, F>,
    offline: OfflineWord,
}

Note that word in OfflineWord is in reality a Newtype but I have replaced it here since the newtype only represents processing and this way the snippet is MRE.

The file field is intended to stored a shared reference to a valid system path so it can be reused to open a file for all instances of OnlineWord. In other words, all words share a single origin file.

Whole error message:

error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
  --> src/rspeer_freq.rs:20:5
   |
20 |     online: OnlineWord<'file, F>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
help: wrap the field type in `ManuallyDrop<...>`
   |
20 |     online: std::mem::ManuallyDrop<OnlineWord<'file, F>>,
   |             +++++++++++++++++++++++                    +

For more information about this error, try `rustc --explain E0740`.

As seen the structs implement Copy by derive and each field does so too (including &T) but compiler is still complaining about them not having Copy (or ManuallyDrop).

rustc --explain E0740 Gives a slightly different explanation, saying that no fields in a union may have destructors. Though I have no powers over that aside from not implementing them, Copy should automatically deal with that by just forgetting the memory AFAIK.

The generic type F in OnlineWord does not have a requirement for Copy but that should not be a problem since 1. derive(Copy) is not complaining 2. &T, as mentioned, has blanket Copy impl. Including Copy as a requirement removes the error but in my understanding it should not be there in the first place.

What am I doing wrong/Misunderstanding here, or is this a bug/limitation within the compiler?

A better way of doing this is encouraged but not required for answering this post.


Solution

  • derive(Trait) on a generic type works by bounding all generic parameters on Trait, therefore your #[derive(Copy)] is only applicable when F: Copy, even though it is not needed. There is a desire for a "smarter" derive called "perfect derive", but nothing is implemented yet (also, it cannot currently work in all cases due to some type system quirks).

    You can manually implement Copy and Clone.