Skip to content

&raw const some_union.field erroneously requires unsafe #141264

@kupiakos

Description

@kupiakos

I tried this code:

#[repr(C)]
union Foo {
    x: u8,
    y: u32,
}

impl Foo {
    fn zero_first_byte(&mut self) {
        let p = &raw mut self.x;
        unsafe { *p = 0 }
    }
}

I expected to see this happen: &raw mut self.x should be a safe operation, because it consists only of in-bounds pointer arithmetic and does not construct a reference or value to uninit. An equivalent using offset_of! is safe:

// wrapping_add is used because the compiler's knowledge of the field offset being in-bounds is lost.
let p: *mut u8 = ptr::from_mut(self).wrapping_byte_add(mem::offset_of!(Self, x)).cast();

Instead, this happened:

error[E0133]: access to union field is unsafe and requires unsafe block
  --> src/lib.rs:12:26
   |
12 |         let p = &raw mut self.x;
   |                          ^^^^^^ access to union field
   |
   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior

This indicates that Rust is blanket-banning access to the place self.x without consideration for how that place is used. This seems to be an oversight in adding ptr::addr_of! and the &raw operation. It is unsafe to construct a reference or move from such a place, but it should be safe to spell the place and get a raw pointer to it.

This should instead act more like access to packed fields: spelling packed_val.unaligned_field only errors when constructing a reference to that field - merely spelling the place, moving, or using &raw const packed_val.unaligned_field is accepted in safe code.

Meta

rustc --version --verbose:

rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1

Occurs on current stable, beta, and nightly (2025-05-18 4d051fb306e661654d08).
No backtrace was emitted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.T-langRelevant to the language teamT-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions