E0506 line order matters

#1

Hi All

I’m trying to understand how rustc avoids data races and wrote the following piece of code:
let mut x: i32 = 0;
let rx = &mut x;
x = 1;
*rx = 2;
To avoid data race rustc emits E0506 cannot assign to `x` because it is borrowed .
I understand this. But if i change order of lines it compiles successfully playground :
let mut x: i32 = 0;
let rx = &mut x;
*rx = 2;
x = 1;
I expected that rustc detects presence of variable/mutable reference depending on scope and order of lines does not matter. Is rustc smarter?
I also wrote code using a heap type playground :
let mut v: Vec = Vec::new();
v.push(0);
let vr1 = &mut v;
v[0] = 6;
vr1[0] = 5;
It also exhibits the same issue with line order. If I exchange the two last lines, it is compiled.

Thanks, Slava

#2

Hi, your code compiles because of non lexical lifetime, ( link to the rfc). It enables the compiler to drop reuse a variable before the end of the scope if it’s not used. So the compiled code looks something like this.
Edit: this is just wrong.

#3

NLL is a feature added in the 2018 edition. 2015 edition is still based on lexical scopes, like what you had expected. The drop-down menu on the playground will let you change editions, and you can see this effect.

#4

@leudz FYI drops are not actually reordered like you suggest, and in fact even your explicit drop was not enough to fix code in 2015 edition. NLL only refines the range where values are considered borrowed. If your type implements Drop, this still executes at the end of the lexical scope.

1 Like
#5

I was more suggesting that rx stops existing not that x is dropped. A way to make it work in the 2015 edition is this but I think it’s less impactful, maybe I should stick to the correct one?

#6

Ok, but it doesn’t stop existing! If that were a wrapper type like struct Ref(&mut i32) which implemented Drop, then it would still last until the end of its scope or an explicit drop. And in that case, the borrow would also be extended to the drop point, even with NLL.

NLL doesn’t change drop semantics. But in cases where there’s no drop implementation, like with the bare reference, NLL will let the borrowed lifetime end sooner, releasing that value to be used elsewhere.

I’m arguing semantics, but these semantics are important to the question.

1 Like
#7

Thank leudz for the link to the RFC. Now I understand this much better.
Thank cuviper for answer refining.