Bad diagnostic: does not explain *why* `Copy` trait did not get derived
Open
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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