Skip to content

When matching on enums, read the discriminant even if there's only a single variant#154756

Open
meithecatte wants to merge 3 commits intorust-lang:mainfrom
meithecatte:always-always-discriminate
Open

When matching on enums, read the discriminant even if there's only a single variant#154756
meithecatte wants to merge 3 commits intorust-lang:mainfrom
meithecatte:always-always-discriminate

Conversation

@meithecatte
Copy link
Copy Markdown
Contributor

@meithecatte meithecatte commented Apr 3, 2026

This is a follow-up to #150681, where it has been decided that this change should land in a separate PR.

This PR removes a special case, so that matching on enums that only have a single variant still emits a discriminant read in MIR. This is motivated by some weirdness being caused by this special case:

  1. If a single-variant enum is marked with #[repr(u8)], it will get an actual discriminant that's there in memory, and if it is set to an invalid value or left uninitialized, we would like to say that's UB. Recall the example from the previous PR:

    #![allow(dead_code)]
    use core::mem::{size_of, transmute};
    
    #[repr(u8)]
    enum Inner {
        X(u8),
    }
    
    enum Outer {
        A(Inner),
        B(u8),
    }
    
    fn f(x: &Inner) {
        match x {
            Inner::X(v) => {
                println!("{v}");
            }
        }
    }
    
    fn main() {
        assert_eq!(size_of::<Inner>(), 2);
        assert_eq!(size_of::<Outer>(), 2);
        let x = Outer::B(42);
        let y = &x;
        f(unsafe { transmute(y) });
    }
  2. The presence of the discriminant read changes the behavior of closure captures, and can therefore be observed through the borrow checker and drop order. As such, #[non_exhaustive] on a single-variant enum must force a discriminant read, just like if the enum had multiple variants. However, having the runtime semantics depend on the presence of the #[non_exhaustive] attribute is not ideal. Moreover, it creates edge cases where removing a #[non_exhaustive] attribute from a public enum is a breaking change.

Fixes #147722.
Fixes #151786.
Fixes rust-lang/cargo#16417.

From a previous attempt at this change, we have had a couple of regressions on crater – though some of those already got addressed. A preliminary glance suggests that none of the issues should be hard to fix though.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 3, 2026

The Miri subtree was changed

cc @rust-lang/miri

Some changes occurred in match lowering

cc @Nadrieril

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 3, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 3, 2026

r? @mati865

rustbot has assigned @mati865.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 69 candidates
  • Random selection from 11 candidates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

3 participants