Skip to content

Vec iterator causes double mutable borrow compile error #43437

Closed
@ivanbakel

Description

@ivanbakel

Alternative title: Multiple simultaneous overlapping mutable borrows.

I shouldn't find an existing issue on this, and it doesn't seem to me like a code error - at least, nothing in the documentation suggested to me that this was expected. At the very least, the error message is unclear if it is expected.

MRE:

struct Test<'a, T : 'a> {
    contents : &'a mut T,
    function : &'a fn(&'a mut T) -> ()
}

impl<'a, T : 'a> Test<'a, T> {
    fn do_thing(self) {
        let v : Vec<()> = vec![];
        for item in v.iter() {
            match (self.function)(self.contents) {
                () => {}
            }
        }
    }
}

Expectation:
This would compile. The mutable borrows don't overlap.

What happens:
rustc complains that self.contents is mutably borrowed twice at the same position.

 error[E0499]: cannot borrow `*self.contents` as mutable more than once at a time
   |
28 |             match (self.function)(self.contents) {
   |                                   ^^^^^^^^^^^^^
   |                                   |
   |                                   second mutable borrow occurs here
   |                                   first mutable borrow occurs here
...
32 |     }
   |     - first borrow ends here

This is the only compiler error in the program. Any fixes to this error will cause the entire thing to compile successfully.

From testing, things that will prevent this:

  • Removing the outside vec iterator
  • Using a named external function with the same signature instead of a function from a field of Test.

Things that will not prevent this:

  • Using a function impl'd on a field of Test - e.g.

     struct FunctionWrapper<'a, T : 'a> { inner_func : ... }
     impl<a, T : 'a> FunctionWrapper<'a, T> { fn call(&self, arg : &'a mut T) { (self.inner_func)(arg) } }
     struct Test<'a, T : 'a> { function : FunctionWrapper<...> }
    

    This is true even if you're not calling a stored function - a stored function was just the simplest example I could think of.

  • Passing in the value which is the argument of the function. fn do_thing(self, other : &'a mut T) will still complain of a double borrow at the same position of other

Meta

Tested on

  • rustc 1.19.0 (stable)
  • rustc 1.20.0-nightly

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions