[ NEWBIE ] mutable borrow later used here

Hi Everyone :slight_smile:

can anyone please explain why this code want compile, i want to understand the reason behind why the second dbg is an error. (like what kind of security issue does it prevent..) why is it restricted in this example ?

fn test(x: &mut usize) -> &usize {
    x
}

fn main() {
    let mut x = 5;
    let y = test(&mut x);

    dbg!(x);
    dbg!(y);
}

the error

error[E0503]: cannot use `x` because it was mutably borrowed
  --> src/main.rs:9:5
   |
7  |     let y = test(&mut x);
   |                  ------ borrow of `x` occurs here
8  |
9  |     dbg!(x);
   |     ^^^^^^^ use of borrowed `x`
10 |     dbg!(y);
   |          - borrow later used here
   |
   = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0503`.
error: could not compile `rust_blog` due to previous error

You migh be aware of the fact that Rust doesn’t permit holding an immutable reference and a mutable reference to the same thing at once. It might look like that’s not the case here; however using your function takes_shared_ref couples the lifetime of the returned immutable reference to the parameter mutable reference. As long as you keep the returned reference, you still cannot create any other immutable references to the same variable (except by copying b).

You might think that turning &mut i32 into &i32 should get rid of this restriction; but Rust doesn’t support “downgrading” references like that (in a way that would lift the restrictions that holding a mutable reference would entail). Something like this also appears – with some more explanation – in a blog post as a “common lifetime misconception”, phrased as the misconception “downgrading mut refs to shared refs is safe”:

that's the part i was reading, and i am a bit confused, as why it is prevented on my case, what is wrong about the code i wrote, that makes the compiler complain, and by wrong i mean, what security issue would happen from this code.

i am sorry in advance about my bad english

The concrete example you have doesn’t really provide much reason for why the thing you tried is disallowed. However it’s hard to formulate general rules for when the compiler would be allowed to automatically infer that such “downgrading” happened. There are functions that return “immutable” references that don’t actually fully downgrade the reference. For example Cell::from_mut returns an “immutable/shared” reference to a Cell that still allows mutation of the contained value.

Also, if the function is no longer generic, but expects 'static lifetime, so

fn test(x: &'static mut usize) -> &'static usize {
    x
}

then the function is no longer known to be “downgrading” the mutable reference either, because it could just stash the original &'static mut usize into some global (static) variable and return an unrelated &'static usize.


The only way that Rust could ever support “downgrading mutable reference” in my personyl view, is if there was an explicit way to write it into the function signature; i.e. some kind of reference that’s mutable for a short lifetime and then downgrades into an immutable reference for a longer lifetime. Suppose (pseudo-syntax) something like

fn test<'short, 'long>(x: &'short 'long mut_then_shared usize) -> &'long usize {
    *x += 1; // mutation possible in `'short` lifetime, e.g. inside of this function
    x // can be turned into longer-lived `&'long usize` reference
}

Rust does not have any such feature (yet?) but it seems possible to me; so the main reason for now then is: technical limitations; the current borrow-checker does not allow something like this because it’s hard to generalize, one would probably need to design and implement more language features, etc..

1 Like

I think the real reason is very simple:

Rust dosen't allow two have mutable references in use. In your example, test() returns a second mutable reference to x.

If you use both (x and y) after the call to test(), you violate this basic rule. If you use only one of them, there is no problem.