Why we can have two living mutable refs with rust > 1.35?

This code doesn't compile with rust == 1.35 but is validated by the borrow checker of later versions. What changes of the borrowing rules make that possible ?

fn main()
{
    let mut x = 0;

    let r_x = &mut x;
    *r_x = 0;

    let r_x_2 = &mut (*r_x);

    *r_x_2 = 8;
    *r_x = 7;

    println!("{}", x);
}

It's called non-lexical lifetimes (NLL). You can google that expression for more information.

1 Like

The reason why intuitively the compiler accepts this code is that after the *r_x_2 = 8; line the variable r_x_2 is no longer considered alive, and thus r_x becomes usable again.

With the 1.35 version of the compiler you had to manually add scopes to hint this to the compiler:

fn main() {
    let mut x = 0;
    {
        let r_x = &mut x;
        *r_x = 0;
        {
            let r_x_2 = &mut (*r_x);
            *r_x_2 = 8;
        }
        *r_x = 7;
    }
    println!("{}", x);
}
3 Likes

Thanks for your fast answers.

Yes, indeed, that's that.

What puzzled me the most was the fact that if I replace &mut (*r_x) by &mut x it doesn't pass. So I guess the compiler consider we can borrow from a borrow, which I didn't take into account in my mental model.

1 Like

Speaking of mental models... Here's a fun thread to look into in case your goal is (to read a shit-ton of large amount of replies and) to deepen, or improve, your “mental model” for borrowing.

2 Likes

Thanks @steffahn I found your reply about reborrowing. Now I know how to name that. :slight_smile:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.