UPDATE: This is fixed by the MIR-based borrow checker and just needs a test. See the mentoring instructions below.
Currently, the borrow checker thinks that the RHS of += is evaluated before the LHS. trans thinks that the LHS is evaluated before the RHS. The disagreement leads to bad results.
fn main() {
let x = Box::new(0);
let mut y = 0;
*{ drop(x); &mut y } += *x;
assert_eq!(y, 0);
}
triage: P-medium
Also fixed by MIR (almost a dup of #28160, but not quite)/
See this internals thread: https://internals.rust-lang.org/t/settling-execution-order-for/4253
So the internals thread says this: "before MIR, we were actually quite inconsistent here, in that borrowck and trans disagreed on some of the particulars. MIR eliminated that inconsistency, but there are still some matters that we should try to resolve -- and quick!" If that's the case, then this should be closed. @nikomatsakis Is this the case?
Well, we're not yet running the borrowck on MIR, so I'm not sure.
But certainly the example seems to work ok now.
Assignment operators are still wrong, which can lead to use-after-free:
use std::ops::AddAssign;
struct MyVec<T>(Vec<T>);
impl <T> Drop for MyVec<T> {
fn drop(&mut self) {
println!("Being dropped.");
}
}
impl<T> AddAssign<T> for MyVec<T> {
fn add_assign(&mut self, _elem: T) {
println!("In add_assign.");
}
}
fn main() {
let mut vec = MyVec(vec![0]);
let mut vecvec = vec![vec];
vecvec[0] += {
vecvec = vec![];
0
};
}
Prints
Being dropped.
In add_assign.
Credit to @xfix for bringing this up in https://github.com/rust-lang/rfcs/pull/2025#issuecomment-308808143, I just weaponized it.
@RalfJung's example gets an error with MIR borrowck enabled (as expected):
https://play.rust-lang.org/?gist=761478ea89b3cd1df50ee274cb7a909d&version=nightly
I am filing this under "bugs fixed by MIR borrowck" https://github.com/rust-lang/rust/issues/47366
Marking as E-needstest and E-mentor:
Since this code works now, what we need to do is add it to our test-suite. To do that, you would create a file in src/test/ui/nll named issue-27868.rs containing the example I linked to here. There are general instructions for adding new tests here.
Apparently PR #53326 added the desired test here. So this is NLL-fixed-by-NLL now, I think.
NLL (migrate mode) is enabled in all editions as of PR #59114.
The only policy question is that, under migrate mode, we only emit a warning on this (unsound) test case. Therefore, I am not 100% sure whether we should close this until that warning has been turned into a hard-error under our (still in development) future-compatibility lint policy.
Most helpful comment
Assignment operators are still wrong, which can lead to use-after-free:
Prints
Credit to @xfix for bringing this up in https://github.com/rust-lang/rfcs/pull/2025#issuecomment-308808143, I just weaponized it.