Mut borrow lifetime expanded to the enclosing function

76a52c4
Opened by Carol Schulze at 2020-06-11 18:05:22

Both Rust stable (v1.14) and nightly (468227129 2017-01-03), regardless of optimization flags, will expand the lifetime of an &mut borrow to the enclosing function in a fairly specific case. Here's a minimal snippet that will trigger the bug:

fn foo<'a>(_: &'a mut [&'a str; 0]) {}

fn bar(_: &mut [&str; 0]) {}

fn main() {
    let mut a = [];
    foo(&mut a);
    bar(&mut a);
}

rustc fails with cannot borrow 'a' as mutable more than once at a time. This bug still happens if the array is replaced by at least Vecs and HashMaps. However, it compiles fine if foo takes a slice instead of an array, or if either or both inner and outer lifetime constraints are removed from foo's argument.

I don't know if this is relevant or not, but I compiled my original code with -Z dump-mir both before and after the commit that hit this bug, with both stable and nightly, and the dumped mir for the function that does the borrows is the same in all instances.

  1. I'm now also hitting a case where a simple immutable borrow for a function argument lives longer than the concrete value. Something akin to this:

    fn foo<'a, T: SomeTrait>(_: &mut T, _: &'a SomeStruct<'a>) {...}
    
    fn main() {
        let mut a = ...;
        let b = SomeStruct::new(...);
        foo(&mut a, &b);
    }
    

    rustc errors out with b does not live long enough, saying that &b lives past the end of the function, outliving b. I'm still trying to find a small test case.

    Both the previous and this error seem to be related to passing an argument with explicit lifetimes in the form &'a SomeStruct<'a>and rustc somehow assigning 'a to a bigger scope than necessary. I'm still fairly new to Rust but &'a SomeStruct<'a> looks ok to me, and is actually the form suggested by rustc to solve some "conflicting requirements".

    Carol Schulze at 2017-01-31 11:12:26