In issue 73987 discusses unsafe { &raw const (*ptr).data }
as the (only?) way to get a raw pointer to a field. But it doesn't seem to be raw enough for this situation. We have a mutable reference to a part, and we want a reference to another part.
#![feature(raw_ref_op)]
struct Data { a: i32, b: i32 }
#[repr(transparent)]
struct S { data: Data }
fn main() {
let miri_have_mercy = 0;
let mut s = S { data: Data { a: 4, b: 2 } };
let ptr = &mut s as *mut S;
let data = unsafe { &mut (*ptr).data };
let ra = &mut data.a;
let data = match miri_have_mercy {
0 => unsafe { &raw const (*ptr).data },
1 => unsafe { &raw mut (*ptr).data },
_ => ptr as *const Data,
};
let rb = unsafe { &(*data).b };
println!("{}{}", *ra, *rb);
}
This outputs the correct answer, but has Miri complaining on the *ra
in the last line about "Undefined Behavior: trying to reborrow for SharedReadOnly, but parent tag <3686> does not have an appropriate item in the borrow stack". MIRIFLAGS=-Zmiri-track-pointer-tag=3686
has Miri explaining that the so-called raw field access "popped tracked tag for item [Unique for <3686>]". Where is the undefined behavior in this code?
Or how can we legally get to a field's address? Changing the miri_have_mercy
constant to pick either of two alternatives makes Miri quiet again, but I know that Miri closes its eyes for some forms of abuse.