rust-lang / rust-lang/rust

Bad diagnostic: does not explain *why* `Copy` trait did not get derived

Open
#151,522 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

Code

https://godbolt.org/z/1bdzezjEa

// BAD:
pub trait Trait {}
// GOOD:
//pub trait Trait : Clone+Copy{}

#[derive(Debug, Clone, Copy)]
struct TypeA {
    field_a: usize,
}

impl TypeA {
    fn new(field_a: usize) -> Self {
        Self { field_a }
    }
}

impl std::ops::Deref for TypeA {
    type Target = usize;

    fn deref(&self) -> &Self::Target {
        &self.field_a
    }
}

impl From<usize> for TypeA {
    fn from(field_a: usize) -> Self {
        Self { field_a }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct TypeB<T>
where
    T: Trait,
    core::marker::PhantomData<T>: Clone + Copy,
{
    field_a: usize,
    _phantom: core::marker::PhantomData<T>,
}

impl<T> std::ops::Deref for TypeB<T>
where
    T: Trait,
{
    type Target = usize;

    fn deref(&self) -> &Self::Target {
        &self.field_a
    }
}

impl<T> TypeB<T>
where
    T: Trait,
{
    pub fn new(field_a: usize) -> Self {
        Self {
            field_a,
            _phantom: core::marker::PhantomData,
        }
    }
}

#[derive(Debug)]
struct TypeC;

impl<T> TryFrom<TypeB<T>> for TypeA
where
    T: Trait,
{
    type Error = TypeC;

    fn try_from(value: TypeB<T>) -> Result<Self, Self::Error> {
        Ok(Self::new(*value))
    }
}

#[derive(Debug, Clone, Copy)]
struct TypeD<T, R>
where
    T: Trait,
    R: std::ops::RangeBounds<TypeB<T>>,
{
    range: R,
    _phantom: core::marker::PhantomData<T>,
}

impl<T, R> TypeD<T, R>
where
    T: Trait,
    R: std::ops::RangeBounds<TypeB<T>>,
{
    fn new(range: R) -> Self {
        Self {
            range,
            _phantom: std::marker::PhantomData,
        }
    }
}

impl<T, R> From<R> for TypeD<T, R>
where
    T: Trait,
    R: std::ops::RangeBounds<TypeB<T>>,
{
    fn from(value: R) -> Self {
        Self::new(value)
    }
}

impl<T> TryFrom<TypeD<T, std::ops::RangeInclusive<TypeB<T>>>>
    for std::ops::RangeInclusive<usize>
where
    T: Trait,
{
    type Error = TypeC;

    fn try_from(
        range: TypeD<T, std::ops::RangeInclusive<TypeB<T>>>,
    ) -> Result<Self, Self::Error> {
        let range = range.range;
        let start = TypeA::try_from(*(range.start()))?;
        // let end = TypeA::try_from(*range.end())?;
        // Ok(std::ops::RangeInclusive::new(*start, *end))
        unimplemented!()
    }
}
Current output
error[E0507]: cannot move out of a shared reference
   --> <source>:122:37
    |
122 |         let start = TypeA::try_from(*(range.start()))?;
    |                                     ^^^^^^^^^^^^^^^^ move occurs because value has type `TypeB<T>`, which does not implement the `Copy` trait
    |
note: if `TypeB<T>` implemented `Clone`, you could clone the value
   --> <source>:32:1
    |
 32 | pub struct TypeB<T>
    | ^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
122 |         let start = TypeA::try_from(*(range.start()))?;
    |                                     ---------------- you could clone this value

warning: unused variable: `start`
   --> <source>:122:13
    |
122 |         let start = TypeA::try_from(*(range.start()))?;
    |             ^^^^^ help: if this is intentional, prefix it with an underscore: `_start`
    |
    = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default

error: aborting due to 1 previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0507`.
Compiler returned: 1
Desired output
It should point out that `TypeB` isn't `Copy`able because `core::marker::PhantomData<T>` isn't *actually* copyable, because `T` isn't `Copy`able itself.
I was not able to derive that from the current diag.
Rationale and extra context

No response

Other cases

Rust Version
rustc 1.95.0-nightly (5c49c4f7c 2026-01-20)
binary: rustc
commit-hash: 5c49c4f7c8393c861b849441d27f5d40e0f1e33b
commit-date: 2026-01-20
host: x86_64-unknown-linux-gnu
release: 1.95.0-nightly
LLVM version: 21.1.8
Compiler returned: 0
Anything else?

If T isn't Copyable, perhaps

    core::marker::PhantomData<T>: Clone + Copy,

should fail too?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the E0507 diagnostic from the Godbolt example, focusing on source line 122 and the derived Copy implementation for TypeB. Trace the compiler's diagnostic handling for this move error and add coverage for the example; done means the message explains that TypeB is not Copy because its PhantomData requires T to be Copy.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.