Rc<T> sometimes cannot be cloned?

I ran into a situation in which the Rust compiler rejects code I thought is valid. At the bottom of this message is a sample program demonstrating the compiler error. Compiler version is 1.42.0.

Summarizing the problem, I thought Rc<T> always implements Clone for any type T—even if T doesn't implement Clone. Indeed, by itself in my program, Rc<B> implements Clone without the type B implementing Clone. However, when I contain Rc<B> in my struct, the struct fails derive the Clone trait, and I get a compiler error when I attempt to call the clone method on it.

What's going on? What am I missing?

Also, I'm not looking for a workaround. I can explicitly implement Clone rather than using the derived implementation to work around this problem. Instead, I'm looking to broaden my understanding of why this program is invalid.

Thanks!

use std::rc::Rc;

#[derive(Clone, Debug)]
struct A<T> {
    inner: Rc<T>,
}

#[derive(Debug)]
struct B;

#[derive(Clone, Debug)]
struct C;

fn main() {
    {
        let a1 = Rc::new(B);
        let a2 = a1.clone(); // OK
        dbg!(a2);
    }

    {
        let b = B;
        let a1 = A { inner: Rc::new(b) };
        let a2 = a1.clone(); // ERROR: error[E0599]: no method named `clone` found for struct `A<B>` in the current scope
        dbg!(a2);
    }
    {
        let c = C;
        let a1 = A { inner: Rc::new(c) };
        let a2 = a1.clone(); // OK
        dbg!(a2);
    }
}

Here is the compiler output.

$ rustc --version
rustc 1.42.0 (b8cedc004 2020-03-09)

$ cargo check
    Checking rust v0.0.0 (/home/cbrandenburg/Art/scratch/rust)
error[E0599]: no method named `clone` found for struct `A<B>` in the current scope
  --> src/main.rs:24:21
   |
4  | struct A<T> {
   | ----------- method `clone` not found for this
...
24 |         let a2 = a1.clone(); // ERROR: error[E0599]: no method named `clone` found for struct `A<B>` in the current scope
   |                     ^^^^^ method not found in `A<B>`
   |
   = note: the method `clone` exists but the following trait bounds were not satisfied:
           `A<B> : std::clone::Clone`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `clone`, perhaps you need to implement it:
           candidate #1: `std::clone::Clone`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: could not compile `rust`.

To learn more, run the command again with --verbose.

It's not Rc's issue, but #[derive(Clone)]'s. It generates code like below. You can check the actual code via cargo-expand command.

#[derive(Clone)]
struct Foo<T> {...}

// generates

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

For more context, you can check this issue.

3 Likes

Try using this code:

let a2 = Rc::clone(&a1);

In the meantime you can use ::derivative:

#[macro_use]
extern crate derivative;

#[derive(Debug, Derivative)]
#[derivative(Clone(bound=""))]
struct A<T> {
    inner: Rc<T>,
}

or implement Clone manually:

#[derive(Debug)]
struct A<T> {
    inner: Rc<T>,
}

impl<T> Clone for A<T> {
    #[inline]
    fn clone (self: &'_ Self) -> Self
    {
        Self {
            inner: self.inner.clone(),
        }
    }
}

EDIT: Removed an accidental : Clone bound I had added

2 Likes

You accidentally kept the Clone bound on T!

3 Likes

:rofl: damn, I've gotten to the point where I do think like the Rust compiler without even knowing :sweat_smile: :rofl:

6 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.