Why is addr_of_mut causing a borrow error?

I'm confused as to why this code:

use std::ptr::{addr_of, addr_of_mut};

struct Pair {
    x: u32,
    y: u32,
}

fn main() {
    let mut p = Pair { x: 1, y: 2 };
    {
        let p: *mut Pair = &mut p;
        unsafe {
            let get = || addr_of!((*p).x).read();
            let y = addr_of_mut!((*p).y);
            y.write(get());
        }
    }
    println!("x={} y={}", p.x, p.y);
}

produces this error:

error[E0502]: cannot borrow `p.y` as mutable because it is also borrowed as immutable
  --> src/main.rs:14:21
   |
13 |             let get = || addr_of!((*p).x).read();
   |                       --          ------ first borrow occurs due to use of `p` in closure
   |                       |
   |                       immutable borrow occurs here
14 |             let y = addr_of_mut!((*p).y);
   |                     ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
15 |             y.write(get());
   |                     --- immutable borrow later used here
   |
   = note: this error originates in the macro `addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

I thought borrow checking did not happen with pointers. Can anyone explain what's going on here? Thanks!

Playground link: Rust Playground

|| addr_of!((*p).x).read() captures a reference to p (of type &*mut Pair) and then addr_of_mut!((*p).y) requires invalidating this reference. Try using move || addr_of!((*p).x).read() to capure a copy of p (of type *mut Pair) instead.

I don't understand why addr_of_mut needs to invalidate the reference taken by the closure; the pointer p is not mut and is not modified in any way, only the pointed-at data is. Note that the error refers to p.y (the pointed-at data), not p.

FWIW adding move to the closure does get rid of the error.

Hmm, interesting. My guess is the borrow checker is running on &raw [mut]. The RFC implies it should be fine to ignore the error by my reading, but opsem confirmation would be best.

Here's a slightly minified version. You could open a ticket about it.

(All that being said, just avoiding the & *mut Pair via move is still what you want for the OP.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.