Why does the borrow checker complain here?

This code

fn main() {
    let mut i;
    let mut v = Vec::<&i32>::with_capacity(1);
    let mut v_ptr = v.as_mut_ptr();
    std::mem::forget(v);
    for _ in 0..3 {
        let mut v = unsafe { std::mem::ManuallyDrop::new(Vec::from_raw_parts(v_ptr, 1, 0)) };
        i = 5;
        v.push(&i);
        v.clear();
        v_ptr = v.as_mut_ptr();  // Code compiles after removing this line.
    }
    unsafe {
        Vec::from_raw_parts(v_ptr, 1, 0);
    }
}

fails to compile with the error

error[E0506]: cannot assign to `i` because it is borrowed
 --> src/main.rs:8:9
  |
8 |         i = 5;
  |         ^^^^^ assignment to borrowed `i` occurs here
9 |         v.push(&i);
  |         -      -- borrow of `i` occurs here
  |         |
  |         borrow later used here

The code compiles when removing the raw pointer assignment v_ptr = v.as_mut_ptr(); inside the loop.

I don't understand why this is happening. It looks like the borrow checker is figuring out that the vector is reused in the next iteration based on the raw pointer assignment, which goes against mostly everything I thought to know about the borrow checker.

(I'm aware that my code doesn't make any sense. The only thing I'm trying to achieve is understanding whether this is a compiler bug or a misunderstanding on my part.)

This is becaue v_ptr has the type *mut &'a i32, for some specific lifetime 'a. This means that every assignment to the v_ptr variable must use the same lifetime, and each borrow of i must be valid for that full shared lifetime.

2 Likes

Thanks, of course! I mentally got the type of v_ptr wrong and thought it's *mut i32. The behaviour is really reasonable, but the error message is not very helpful in this case. :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.