Mutable borrow automatically changes to immutable? - rust

It seems that u, a mutable borrow, becomes automatically immutable in
let v = &*u;
Both u and v are then immutable borrowed references so they are both allowed.
use std::ascii::AsciiExt;
fn show(a: &str) {
println!("a={}", a);
}
fn main() {
let mut t = String::new();
t.push('s');
let u = &mut t;
u.make_ascii_uppercase(); // u is really mutable here
let v = &*u; // u became immutable to allow this?
show(u); // both u and v are now accessible!
show(v);
}
Outputs:
a=S
a=S
If I try to use u as a mutable borrow after
show(v);
compiler will recall that
let v = &*u;
is really not allowed:
cannot borrow `*u` as mutable because it is also borrowed as immutable
Is it a bug or is there really some "automatically convert mutable borrow to immutable when mutability is no longer needed" principle? I am using Rust 1.13.0.

A mutable reference can be borrowed immutably, however this is not what is happening here.
When forming a reference with &, you need to be explicit about mutability; unless you specify &mut it will be an immutable reference.
Your example can be reduced to:
use std::ascii::AsciiExt;
fn main() {
let mut t = "s".to_string();
let u = &mut t;
u.make_ascii_uppercase();
let v = &*u;
let () = v;
}
The last line is a trick to get the compiler to tell us (in the error message) what the type of v is. It reports:
error[E0308]: mismatched types
--> <anon>:9:9
|
9 | let () = v;
| ^^ expected reference, found ()
|
= note: expected type `&std::string::String`
= note: found type `()`
Here we have:
u: an immutable binding, which is a mutable borrow of t
v: an immutable binding, which is an immutable re-borrow of t through u
If, however, I change the v line to let v = &mut *u;, then I get expected type '&mut std::string::String' and then we have:
u: an immutable binding, which is a mutable borrow of t
v: an immutable binding, which is a mutable re-borrow of t through u
The important concept here is re-borrowing, which is what &*u and &mut *u are about. Re-borrowing allows forming a new reference from an existing reference:
a re-borrow access the initially borrowed variable
for the lifetime of the re-borrow, the reference from which it is formed is borrowed
The re-borrowing rules are relatively simple, they mirror the borrowing rules:
if you start from an immutable reference:
you can re-borrow it only as an immutable reference, with multiple concurrent immutable re-borrow if you wish
if you start from a mutable reference:
you can either re-borrow it as a mutable reference, exclusively
or you can re-borrow it as an immutable reference, with multiple concurrent immutable re-borrow if you wish
It is interesting to note that a re-borrowed reference can live longer than the reference it was formed from:
fn main() {
let mut t = "s".to_string();
let v;
{
let u = &mut t;
v = &mut *u;
}
v.make_ascii_uppercase();
show(v);
}
This is necessary to ensure that you can return a reference from functions; of course.
So, ultimately, a re-borrow is tracked down to the original borrowed value by the compiler; however, due the re-borrowing mechanics it allows forming an immutable reference to this original value even though a mutable reference is in scope... and simply make sure that this mutable reference is unusable for the lifetime of the new immutable reference.
When a function takes a reference, the compiler automatically introduces a re-borrow at the call site with the appropriate mutability; this is what happens with show here: show(u) really is show(&*u) with a new immutable reference formed for the duration of the function call.

This is confusing, so let's do some experiments.
Your code compiles:
let mut t = String::new();
t.push('s');
let u = &mut t;
u.make_ascii_uppercase(); // u is really mutable here
let v = &*u; // u became immutable to allow this?
show(u); // both u and v are now accessible!
show(v);
What happens if we change the let v line to:
let v = &t;
error[E0502]: cannot borrow t as immutable because it is also borrowed as mutable
--> :12:14
Ok, so that's different. That tells me that &*u, despite being the same type as &t, is not the same; the former is (sub-)borrowing from u, but the latter is trying to reborrow t.
Let's try a different experiment. Putting the previous line back, but now adding something new:
let v = &*u; // the original reborrow
let w = u; // Try to move out of `u`
error[E0502]: cannot borrow t as immutable because it is also borrowed as mutable
--> :12:14
Aha! That confirms that v really is borrowing from u rather than directly from t.
Now, in the original, let's add an attempted mutation via u to the end:
let mut t = String::new();
t.push('s');
let u = &mut t;
u.make_ascii_uppercase(); // u is really mutable here
let v = &*u; // u became immutable to allow this?
show(u); // both u and v are now accessible!
show(v);
u.make_ascii_uppercase();
Now I get:
error[E0502]: cannot borrow *u as mutable because it is also borrowed as immutable
I think that basically explains what's going on:
u borrows t mutably. This stops t being accessed at all directly.
v borrows u immutably. This means that u can still be used immutably, but it can't be used mutably or moved out of.
The other key thing is that you can only use mutable values if the full path to the item is mutable. Since u can't be borrowed mutably while v exists, you can't use *u mutably either. (This last bit is slightly handwavey; I'd welcome further clarifications...)

First of all, u is not mutable at any point, as it was declared with let u, not let mut u. The reason why you can mutate the String it points to is that it holds a mutable reference to it; make_ascii_uppercase() modifies t.
v is also immutable (no mut in let v), so when you call show() that works on immutable references, the borrowing rules are not violated - you can perform multiple immutable borrows at once.

Related

Rust - Why does dereferencing and borrowing break borrowing rules?

As per my understanding, there can be multiple immutable references at a time but if there is a mutable reference it can be the only usable reference.
Why does the following code work?:
fn main() {
let mut y = String::from("bar");
let f: &mut String = &mut y;
let f2: &String = &(*f);
// not allowed since mutable reference already exists
// let f3: &String = &y;
println!("{}, ", f.as_str());
println!("{}", f2.as_str());
}
Edit: Another part of my question which I guess isn't obvious is: why am I not allowed to create f3 (like I am doing in the commented line) when it is exactly the same thing as f2 and created similarly by refrencing y.
Because the compiler is smart enough to know if the data actually is used as mutable before it is used as immutable. If you change the code at all to use the mutable reference first, it fails.
fn main() {
let mut y = String::from("bar");
let f: &mut String = &mut y;
let f2: &String = &(*f);
f.clear();
// not allowed since mutable reference already exists
// let f3: &String = &y;
println!("{}, ", f.as_str());
println!("{}", f2.as_str());
}
Here's a link to a live example. The error, as you'd expect, mentions you cannot have an immutable reference if a mutable one exists.
error[E0502]: cannot borrow `*f` as mutable because it is also borrowed as immutable
--> src/main.rs:6:5
|
5 | let f2: &String = &(*f);
| ----- immutable borrow occurs here
6 | f.clear();
| ^^^^^^^^^ mutable borrow occurs here
...
12 | println!("{}", f2.as_str());
| ----------- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
In short, you can only have one borrow if you have a mutable reference, but the compiler is intelligent enough to know when the value cannot change: in your example, f cannot change when it is used before f2 is used, so it knows it doesn't change.

Why does the compiler error complain about multiple mutable references not dangling reference?

I am trying to understand what exactly happens when functions reborrow mutable references.
fn main() {
let mut a = String::new();
let mut b = String::new();
let aa = &mut a;
let c = my_fun(aa, &mut b);
let d = &mut a;
println!("{}", c);
}
fn my_fun<'b>(x: &'b mut String, y: &'b mut String) -> &'b mut String { y }
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun. But due to the lifetime bound I created in the function signature the reborrow should live at least as long as &mut b exist. So the println force the reborrow to live until it.
Shouldn't this be throwing an error of use after free because the anonymous reborrow has only scope inside my_fun? Outside of this function this reference shouldn't be valid.
But the error I get is:
error[E0499]: cannot borrow `a` as mutable more than once at a time
--> src/main.rs:7:13
|
5 | let aa= &mut a;
| ------ first mutable borrow occurs here
6 | let c = my_fun(aa, &mut b);
7 | let d = &mut a;
| ^^^^^^ second mutable borrow occurs here
8 | println!("{}", c);
| - first borrow later used
which would have made sense if the mutable reference was merely copied instead of reborrowed inside the function.
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun.
It's not quite that.
Let's backtrack a bit: why reborrowing?
There is a fundamental difference between &T and &mut T: &T is Copy, whereas &mut T is not even Clone. The result is that &mut T can only be moved and therefore a call such as:
let x: &mut T = /*...*/;
func(x);
Would result in x being unusable after the call. The work-around would then be to introduce a temporary:
let x: &mut T = /*...*/;
let tmp = &mut *x;
func(tmp);
This temporary would re-borrow the pointee of x, and be consumed by func.
And... that's re-borrowing! The compiler has this "temporary" creation built-in purely for ergonomics!
With that in mind, let's go back to:
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun.
Lifetimes are generally more a range than a point, and this is true here.
The lifetime of tmp in my example above is constrained in 2 ways:
It cannot be greater than that of x.
It cannot be less than that of func.
Which is another way of saying that it can be anything in between those bounds.
I believe you're overthinking "reborrowing" here.
The lifetime requirements you applied say that the thing being referenced by the return value will have at least the lifetime of the things being referenced by the parameters. That's true (and if it weren't provably true, this wouldn't compile). So there is no dangling reference possible.
There isn't a separate "reborrowed" reference. Borrowing is bookkeeping inside the compiler to keep track of lifetimes. There is no let x = &*aa step that actually occurs or is even particularly implied. This isn't like reference counting where memory actually changes at runtime.
Inside of my_fun, y is a reference that's scoped to the function. But the return value is scoped to the caller. (Functions would be impossible to use if this weren't true, having nothing to do with &mut.)

mutably borrow fields from a mutably borrowed struct

from the borrowing rule:
At any given time, you can have either one mutable reference or any number of immutable references.
Below, I have a mutable borrow of the struct Foo (the whole struct), which means I borrow every field of this struct. However, I can have another borrow to its field in demo function. And I suspect I have 2 mutable references to x.a:
#[derive(Debug)]
struct Foo {
a: i32,
b: i32,
}
fn demo(foo: &mut Foo) {
// the `foo` is mutable borrow
// should have exclusive access to all elements of Foo instance
// However,
let bar = &mut foo.a; // second ref to `x.a`
*bar += 1;
let baz = &foo.b;
println!("{:?}", bar);
println!("{:?}", baz);
}
fn main() {
let mut x = Foo { a: 10, b: 1 };
let foo = &mut x; // ref to x, implies borrowing x.a and x.b
demo(foo);
}
I know we can have disjoint mutable borrow to a struct binding (split borrow reference), but I'm not sure whether splitting the reference to a struct violates the borrow rule.
clarification: above code can compile. My confusion is that it should not compile due to the aforementioned reason. (playground)
I found this link relevant.
When you are borrowing a structure mutably, you are then free to borrow any of the sub-elements mutably.
But I can't find any doc to support it.
The line
let bar = &mut foo.a;
creates a reborrow of the a field of foo. As long as the reborrow is alive, the field can't be accessed via foo.a anymore, but only via bar. After the last use of bar, you can use foo.a again – once the reborrow is released, the original borrow is available again.
Reborrowing is very similar to borrowing itself. While a value is borrowed, you cannot access the original value until the borrow is released. The same happens when reborrowing. This makes sure that at any given time there is only a single active mutable borrow, and the borrowing rules are upheld.
The fact that you are dealing with a struct here is incidental. You can do the same with a mutable borrow to any value, e.g. after
let mut i = 17;
let borrow = &mut i;
let reborrow = &mut *borrow;
*reborrow += 4;
*borrow += 21;
the value of i is 42. This code looks like there are multiple active mutable borrows to i. However, at any given time only one of them can be used. The reborrow is released after it is last used, so the original borrow becomes usable again. If we swap the last two lines in this code, it won't compile anymore, since the reborrow would still be alive when borrow is accessed, which is not allowed.
Unfortunately, the mechanics of reborrowing aren't currently documented in the Rust reference. A related, also not well documented topic are implicit reborrows that happen when a mutable reference is bound to a variable of a type that is already known to be a mutable reference.

Nested method calls with existing mutable references

The following code compiles successfully:
let mut v = vec![1];
let r = &mut v;
r.push(r.len());
while this one fails:
let mut v = vec![1];
let r = &mut v;
r.push(v.len());
with error:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
|
| let r = &mut v;
| ------ mutable borrow occurs here
| r.push(v.len());
| ^ immutable borrow occurs here
| r.push(r.len());
| - mutable borrow later used here
Why the first example compiles correctly? Is it because the same reference: r is used in the outer and inner calls? Or is it because it applies the RFC 2025, Two-Phase Borrows? Or something else?
Why the second example fails given that the first example succeeds? Why the RFC 2025, Two-Phase Borrows does not apply here?
I suspect that in the first example there are no errors because the compiler does not create intermediate references and it uses the same reference: r so that there are not multiple borrows.
However, if that is the case, why the following code fails to compile
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);1});
In the second example, v is still mutably borrowed when you try to get its length. Vec::len takes &self, so getting its length would mean borrowing immutably while it's already borrowed mutably.
Accessing len() through r is still ok because you are borrowing through the same borrow, not borrowing it again.
Note that even the first example fails in Rust 1.30 and earlier (or 1.35 with 2015 edition), because it relies on NLL (non-lexical lifetimes). The problem with NLL is that it isn't completely intuitive to know what is allowed. Essentially, it means that borrows that don't outlive the lexical scope of the data are ok, and also several other intuitively correct cases. Your third example is one of the cases that is still not permited by NLL.
1st example:
let mut v = vec![1];
let r = &mut v;
r.push(r.len());
Without the 2-phase borrows the code will not compile because the outer call creates a reborrow of r: &mut *r, and the inner call a new immutable reborrow of the same value: &*r.
With 2-phase borrows, the first reborrow is converted to &mut2 *r and later activated when the second reborrow is out of scope.
2nd example:
let mut v = vec![1];
let r = &mut v;
r.push(v.len());
Even with the 2-phase borrows it does not compile.
The inner call causes a reborrow of v: &mut v that clashes with r.
3rd example:
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);0});
Even with the 2-phase borrows it does not compile.
The inner call requires a &mut2 reborrows of *r that is not allowed by the 2-phase borrows since the outer call already created a &mut2 reborrows of *r.
References:
https://angelocatalani.github.io/2020-12-29-References-and-borrowing-in-Rust/
https://users.rust-lang.org/t/nested-method-calls-with-existing-mutable-references/53345
https://rust-lang.github.io/rfcs/2025-nested-method-calls.html
Why does re-borrowing only work on de-referenced pointers?

How borrow as mutable vs immutable in Rust?

I've read these docs: https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html
I've also read this question: (Cannot borrow immutable borrowed content as mutable)
The docs helped me understand how to declare borrowing as mutable (I think):
let mut (part1, part2) = someTuple;
But I'm haven't been able to find explicit instructions on what borrowing as an immutable looks like. This is my guess:
let (part1, part2) = someTuple;
I know this is a super basic question, but Googling it took me way off into the deep end of explanations and I'm still trying to get my bearings in the most simple of contexts.
How do I borrow as mutable vs an immutable in Rust?
let x = 0;
let immutable_borrow = &x; //borrow as immutable
//to borrow as mutable the variable needs to be declared as mutable
let mut y = 1;
let mutable_borrow = &mut y; //borrow as mutable
Note 1: you can borrow a variable either as immutable or mutable in the same scope, meaning you can't do this:
let mut x = 0;
let immutable_borrow = &x;
let mutable_borrow = &mut x;
Why?
Because if you would have mutable and immutable references of the same variable, then the data of that variable could change through that mutable reference and that could cause a lot of problems.
Note 2: you can immutably borrow a variable endless times but you can mutably borrow a variable only once.
//You can do this
let x = 0;
let x1 = &x;
let x2 = &x;
//...
//But you can't do this
let mut y = 0;
let y1 = &mut y;
let y2 = &mut y; //won't compile if you use y1 after you declare y2
Why?
As mentioned above. One mutable reference could change the data all the other mutable references are poiting to without them knowing. That could cause a lot of problems. But having multiple immutable references is okay, because the data can't be unexpectedly changed.
Ejdrien answers demonstrates the difference between mutable and immutable borrows, however it does not address a subtitle in your question, which is that you are performing borrows as part of pattern matching.
When you write
let (mut part1, mut part2) = someTuple;
you are binding the contents of someTuple to the mutable variables part1 and part2 by moving them. Unless the contents of someTuple were Copyable, the variables part1 and part2 become the exclusive owners of their respective values. If you attempt to access someTuple later by writing, e.g.
println!("{}", someTuple.0);
you'll receive a compile error from the borrow checker that resembles
error[E0382]: borrow of moved value: `someTuple.0`
--> main.rs:6:20
|
4 | let (mut part1, mut part2) = someTuple;
| --------- value moved here
5 |
6 | println!("{}", someTuple.0);
| ^^^^^^^^^^^ value borrowed here after move
In this particular context, there are two ways to inform the compiler that we want to only borrow the contents of someTuple. The first is the technique that Ejdrien described, which is explicitly borrowing the tuple and the performing the pattern matching against then resulting reference:
// Produce two mutable references
let (part1, part2) = &mut someTuple;
// Produce two immutable references
let (part1, part2) = &someTuple;
The problem with this approach is that we are forced to borrow everything in the same way. What if we only want a mutable reference to someTuple.0, and want to retrieve someTuple.1 as a copy, or as an immutable reference? For the tuple example here, this may not seem too critical, but for more complex cases of pattern matching, having this type of control is much more important.
This brings us two the second solution: binding references. Instead of the above, we can write
// Produce two mutable references
let (ref mut part1, ref mut part2) = someTuple;
// Produce two immutable references
let (ref part1, ref part2) = someTuple;
Here, we explicitly state how we want to bind each variable in the pattern matching. The key here is that we are free to intermix mutable and immutable borrows, so the following is also entirely valid:
// Produce immutable reference and one mutable reference
let (ref part1, ref mut part2) = someTuple;
println!("{}", &someTuple.0); // Make a second immutable reference someTuple.0
*part2 = ... // Mutate someTuple.1
println!("{}", part1); // Continue using the immutable reference
If we swap the above with an explicit mutable borrow on the right hand side, we'll once again receive errors from the borrow checker due to simultaneous mutable and immutable references:
let (part1, part2) = &mut someTuple;
println!("{}", &someTuple.0);
*part2 = ... // Mutate someTuple.1
println!("{}", part1);
produces
error[E0502]: cannot borrow `someTuple.0` as immutable because it is also borrowed as mutable
--> main.rs:6:20
|
4 | let (part1,part2) =&mut someTuple;
| -------------- mutable borrow occurs here
5 |
6 | println!("{}", &someTuple.0);
| ^^^^^^^^^^^^ immutable borrow occurs here
...
9 | println!("{}", part1);
| ----- mutable borrow later used here
error: aborting due to previous error

Resources