Skip to content

Misleading error message when mutably referencing members of cloned &T when T does not implement Clone #34629

Closed

Description

@peterjoel

Code example:

#[derive(Debug)]
struct Str {
   x: Option<i32>,
}

fn main() {
    let s = Str { x: None };
    let sr = &s;
    let mut sm = sr.clone();
    foo(&mut sm.x);
}

fn foo(s: &mut Option<i32>) {
    if s.is_none() {
        *s = Some(0);
    }
    println!("{:?}", s);
}

The Error is:

error: cannot borrow immutable field `sm.x` as mutable
  --> <anon>:10:14
   |>
10 |>     foo(&mut sm.x);
   |>              ^^^^

This is misleading because the fix is to add a Clone impl for Str

Meta

rustc --version --verbose:
rustc 1.9.0-nightly (d5a91e6 2016-03-26)
binary: rustc
commit-hash: d5a91e6
commit-date: 2016-03-26
host: x86_64-apple-darwin
release: 1.9.0-nightly

Activity

  1. GuillaumeGomez commented on Jul 4, 2016

    @GuillaumeGomez
    Member

    The biggest question I have is: how can the clone method be called if it isn't defined on Str type?

  2. arielb1 commented on Jul 4, 2016

    @arielb1
    Contributor

    The issue is that <&Str>::clone is called through an autoref.

  3. removed
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Mar 9, 2017
  4. pnkfelix commented on Jan 31, 2019

    @pnkfelix
    Contributor
  5. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Jun 11, 2020
  6. estebank commented on Oct 19, 2023

    @estebank
    Contributor

    Current output:

    error[E0596]: cannot borrow `sm.x` as mutable, as it is behind a `&` reference
      --> src/main.rs:10:9
       |
    10 |     foo(&mut sm.x);
       |         ^^^^^^^^^ `sm` is a `&` reference, so the data it refers to cannot be borrowed as mutable
       |
    help: consider specifying this binding's type
       |
    9  |     let mut sm: &mut Str = sr.clone();
       |               ++++++++++
    

    Applying the suggestion:

    error[E0308]: mismatched types
     --> src/main.rs:9:28
      |
    9 |     let mut sm: &mut Str = sr.clone();
      |                 --------   ^^^^^^^^^^ types differ in mutability
      |                 |
      |                 expected due to this
      |
      = note: expected mutable reference `&mut Str`
                         found reference `&Str`
    

    If you explicitly give sm the type Str expecting the clone to work:

    error[E0308]: mismatched types
     --> src/main.rs:9:23
      |
    9 |     let mut sm: Str = sr.clone();
      |                 ---   ^^^^^^^^^^ expected `Str`, found `&Str`
      |                 |
      |                 expected due to this
      |
    note: `Str` does not implement `Clone`, so `&Str` was cloned instead
     --> src/main.rs:9:23
      |
    9 |     let mut sm: Str = sr.clone();
      |                       ^^
    help: consider annotating `Str` with `#[derive(Clone)]`
      |
    2 + #[derive(Clone)]
    3 | struct Str {
    
  7. estebank commented on Nov 21, 2023

    @estebank
    Contributor

    Another case from #41825:

    use std::collections::BTreeMap;
    use std::collections::HashSet;
    
    #[derive(Debug,Eq,PartialEq,Hash)]
    enum Day {
        Mon,
    }
    
    struct Class {
        days: BTreeMap<u32, HashSet<Day>>
    }
    
    impl Class {
        fn do_stuff(&self) {
            for (_, v) in &self.days {
                let mut x = v.clone();
                let y: Vec<Day> = x.drain().collect();
                println!("{:?}", x);
            }
        }
    }
    
    fn fail() {
        let c = Class { days: BTreeMap::new() };
        c.do_stuff();
    }
    error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
      --> f75.rs:17:31
       |
    17 |             let y: Vec<Day> = x.drain().collect();
       |                               ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
       |
    help: consider specifying this binding's type
       |
    16 |             let mut x: &mut HashSet<Day> = v.clone();
       |                      +++++++++++++++++++
    
    error[E0308]: mismatched types
      --> f75.rs:16:44
       |
    16 |             let mut x: &mut HashSet<Day> = v.clone();
       |                        -----------------   ^^^^^^^^^ types differ in mutability
       |                        |
       |                        expected due to this
       |
       = note: expected mutable reference `&mut HashSet<Day>`
                          found reference `&HashSet<Day>`
    
    E0308]: mismatched types
      --> f75.rs:16:39
       |
    16 |             let mut x: HashSet<Day> = v.clone();
       |                        ------------   ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>`
       |                        |
       |                        expected due to this
       |
       = note: expected struct `HashSet<Day>`
               found reference `&HashSet<Day>`
    note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned instead
      --> f75.rs:16:39
       |
    16 |             let mut x: HashSet<Day> = v.clone();
       |                                       ^
    
  8. added a commit that references this issue on Dec 4, 2023
    6b02b40
  9. added a commit that references this issue on Dec 5, 2023
    f67523d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions