rust-lang / rust-lang/rust

`DerefMut` auto-deref error for `union` fields sometimes doesn't trigger

Open
#141,621 14 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-frontend C-bug I-lang-radar P-lang-drag-1 T-compiler T-lang
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

An implicit DerefMut of a MaybeUninit union field is an error, but sometimes that error does not fire. This is not a soundness issue as it's more like a lint

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=3df4479c28c8a9ce5d2372e161c0e292

use std::mem::ManuallyDrop;

union U {
    x: (),
    f: ManuallyDrop<(Vec<u8>,)>,
}

fn main() {
    let mut u = U { x: () };
    // Errors about the implicit deref of the ManuallyDrop
    unsafe { u.f.0 = Vec::new() };
    // equivalent to (*u.f).0

    let r = &mut u;
    // implicitly derefs the ManuallyDrop but does not error
    unsafe { r.f.0 = Vec::new() };
    // equivalent to (*(*r).f).0
}

I expected to see this happen: Both assignments should error

Instead, this happened: Only the first produces an error

error: not automatically applying `DerefMut` on `ManuallyDrop` union field
  --> src/main.rs:24:9
   |
24 |         a.tup.0.num = 0;
   |         ^^^^^^^
   |
   = help: writing to this reference calls the destructor for the old value
   = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor

We ran into a similar case in https://github.com/rust-lang/rust-clippy/pull/14387

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=223c79eac2bb82ba9834354d2043d67f

use std::mem::ManuallyDrop;

struct Data {
    num: u64,
}

union DataWithPadding {
    u: (),
    tup: (ManuallyDrop<Data>, ()),
}

fn main() {
    let mut a = DataWithPadding { u: () };

    unsafe {
        // No error, but the ManuallyDrop in the tuple is being implicitly dereferenced
        (*&mut a.tup).0.num = 0;
        // equivalent to (*(*&mut a.tup).0).num
        
        // similar
        (&mut a.tup).0.num = 0;

        // Does error when written plainly
        a.tup.0.num = 0;
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the two Rust Playground reproductions linked in the issue and compare the direct and reference-based union-field assignments. Trace the compiler handling of implicit DerefMut for these expressions, then add a regression test showing that both assignments produce the expected error.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.