fpoli
February 21, 2018, 4:01pm
1
Hi! I'm trying to learn how the borrow checker works.
I saw that the borrow checker is run on "validated" MIR, that is different from the final "optimized" MIR.
For example, a move of a mutable reference is _2 = move _1
in optimized MIR, but sometimes it's a _2 = &mut (*_1)
in validated MIR.
My question is: by running the borrow checker on optimized MIR, would it detect all the errors that it would have detected on validated MIR?
1 Like
cuviper
February 21, 2018, 6:14pm
2
I would think that many optimizations will depend on knowing that the input is valid first, even with respect to borrowing, or else that transformation might be invalid itself.
5 Likes
I would think so too, given the comical stuff that comes out of a modern C/++ optimizer when undefined behavior is passed in.
No. For a trivial example, optimized MIR can remove dead code, and you still want checking on that despite it being dead -- especially if it's only dead after inlining, or something. (See a bunch of the bugs that happened with the unsafe
checks moving to MIR, where for a while under a particular nightly feature flag you could call unsafe methods in safe code without an unsafe
block so long as they were dead, IIRC.)
Optimized MIR doesn't even necessarily pass typeck -- for example, it can copy &mut
s:
opened 09:27AM - 01 Dec 17 UTC
closed 10:42AM - 26 May 20 UTC
A-borrow-checker
T-compiler
A-mir
C-bug
https://play.rust-lang.org/?gist=9f782298cc5b0f6cd557baef9e443096&version=nightl… y
```rust
fn blah(mut x: String) {
do_something(&mut x);
}
```
generates the following MIR:
```rust
let mut _0: (); // return pointer
let mut _2: ();
let mut _3: &mut std::string::String;
let mut _4: &mut std::string::String;
bb0: {
StorageLive(_3); // scope 0 at src/main.rs:5:18: 5:24
StorageLive(_4); // scope 0 at src/main.rs:5:18: 5:24
_4 = &mut _1; // scope 0 at src/main.rs:5:18: 5:24
_3 = _4; // scope 0 at src/main.rs:5:18: 5:24
_2 = const do_something(move _3) -> [return: bb1, unwind: bb3]; // scope 0 at src/main.rs:5:5: 5:25
}
```
Which -- though we don't run it again after optimizations -- wouldn't pass `TypeckMir` since it's a copy of a `&mut String`.
That came from InstCombine on the following
```rust
_3 = &mut (*_4); // scope 0 at lib.rs:33:18: 33:24
```
This may or may not be a problem, but I wanted to file it in case it impacts any of the assumptions desired from the Copy/Move split on Operand.
Edit: I suppose this instcombine has long potentially changed the type of the operand, since it doesn't check mutability of the outer `&` or the borrow being `*`d.
cc @eddyb
3 Likes
fpoli
February 22, 2018, 9:52pm
5
Thanks a lot for the answers! That issue points out exactly what I was looking for