-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Description
I'm not sure if this is a bug or not.
#![allow(unused)]
#[repr(C, align(16))]
#[derive(Clone, Copy)]
struct Thing {
x: u128,
y: u64,
// Replace the above line with the below line to make it stop compiling
// y: std::mem::MaybeUninit<u64>,
// 8 bytes of padding here
}
#[derive(Clone, Copy)]
union PreservePad {
thing: Thing,
bytes: [u8; 32],
}
const A: Thing = unsafe {
let mut buffer = [PreservePad { bytes: [0u8; 32] }; 2];
(&raw mut buffer).cast::<&i32>().byte_add(28).write_unaligned(&1);
buffer[0].thing
};
fn main() {}The above code compiles fine, even in Miri. However, changing the y: u64line to y: std::mem::MaybeUninit<u64> causes the following compile error:
error[E0080]: unable to read parts of a pointer from memory at alloc4
--> src/main.rs:21:5
|
21 | buffer[0].thing
| ^^^^^^^^^^^^^^^ evaluation of `A` failed here
|
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
For more information about this error, try `rustc --explain E0080`.
It seems that copying Thing in consteval discards the padding if y is a u64, but copies the padding if y is a MaybeUninit<u64>. This is implemented in the compiler here and here.
Normally, this implementation detail is observable in user code only by, say, printing padding bytes after doing a copy, which is UB. However, the compiler also cares about the contents of padding bytes potentially containing pointer fragments, making the implementation detail observable in user code without invoking UB.
cc @RalfJung
Somewhat related to #147959 and #148259, but this issue doesn't depend on those two issues.
Meta
Reproducible on the playground with stable rust version 1.91.0