rust-lang / rust-lang/rust

Single-variant exception for `match` consequences for `#[non_exhaustive]`

Open
#147,722 28 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-exhaustiveness-checking A-MIR A-miri A-patterns C-discussion I-lang-radar T-compiler T-lang T-opsem
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

bar/src/lib.rs:

#[non_exhaustive]
#[repr(u8)]
pub enum Thing {
    One(u8) = 0,
}

src/main.rs:

use std::mem::MaybeUninit;

use bar::Thing;

fn main() {
    let buffer: [MaybeUninit<u8>; 2] = [MaybeUninit::uninit(), MaybeUninit::new(0u8)];
    let ptr: *const Thing = (&raw const buffer).cast();
    unsafe {
        match *ptr {
            Thing::One(ref _val) => {}
            _ => {}
        }
    }
}

Running the above code in Miri detects UB as follows:

error: Undefined Behavior: reading memory at alloc168[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
 --> src/main.rs:9:15
  |
9 |         match *ptr {
  |               ^^^^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at src/main.rs:9:15: 9:19

Uninitialized memory occurred at alloc168[0x0..0x1], in this allocation:
alloc168 (stack variable, size: 2, align: 1) {
    __ 00                                           │ ░.
}

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

However, if I delete the #[non_exhaustive] line, Miri does not detect any UB.

This seems incorrect. I believe that #[non_exhaustive] is supposed to only affect whether code compiles. It should not affect how code behaves.

It seems that, without #[non_exhaustive], rust does not even read the discriminant. But with #[non_exhaustive], rust does.

Related to:

Meta

rustc --version --verbose:

rustc 1.92.0-nightly (844264add 2025-10-14)
binary: rustc
commit-hash: 844264adda6f41ca6d0d61c4bcac0f263fc5072f
commit-date: 2025-10-14
host: aarch64-apple-darwin
release: 1.92.0-nightly
LLVM version: 21.1.3

cargo miri --version:

miri 0.1.0 (844264adda 2025-10-14)

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 reproducing the example from bar/src/lib.rs and src/main.rs with Miri, comparing behavior with and without #[non_exhaustive]. Read the related issues and pull requests listed in the report to understand the intended match and enum semantics. Done means the behavior is resolved or formally clarified with a regression test covering this case.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.