Lint against cloning references on types that are not Clone


#1

Playground link

struct Foo {}
impl From<Foo> for u32 {
    fn from(f:Foo) -> u32 {
        42
    }
}

fn main() {
    let v = Foo{};
    let a = &v;
    let b = a.clone();
    let c:u32 = b.into();
    println!("{}",c);
}

As expected, the above code didn’t compile, but the error message

error[E0277]: the trait bound `u32: std::convert::From<&Foo>` is not satisfied
  --> src/main.rs:12:19
   |
12 |     let c:u32 = b.into();
   |                   ^^^^ the trait `std::convert::From<&Foo>` is not implemented for `u32`
   |
   = help: the following implementations were found:
             <u32 as std::convert::From<Foo>>
             <u32 as std::convert::From<std::net::Ipv4Addr>>
             <u32 as std::convert::From<char>>
             <u32 as std::convert::From<u16>>
             <u32 as std::convert::From<u8>>
   = note: required because of the requirements on the impl of `std::convert::Into<u32>` for `&Foo`

didn’t show the root cause: the type Foo didn’t implement Clone.

As Clone is really very commonly used, I think it would be a good idea to produce a lint against the line

let b = a.clone();

with a message like

Attampt to clone on a reference that the referenced type didn't implement Clone.
References can be copied so the use of clone is redundent.

#2

Clippy has a Correctness (Deny-by-default) lint for .clone() on &&_, which is this exactly: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_double_ref

Unfortunately this can’t be caught by clippy here because this lint is post- type resolution which can’t be done in this case. Bringing this upstream as a warn-by-default would be great as it could be emitted in this case as well.

Maybe rustc could additionally check if a by-value impl exists when you’re trying to use a ref?