rust-lang/rust · critical

layout decided on a larger discriminant type ({min_ity:?}) t

Error message

layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})

What it means

This panic fires inside LayoutCalculator::layout_of_enum after the minimum integer width needed to represent every enum discriminant value (min_ity) is computed. It asserts that layout never needs more bits than the discriminant type typeck already chose via repr(int)/repr(uN)/repr(iN) (typeck_ity). A violation means codegen would have to truncate a discriminant value that does not fit in typeck's temporary, corrupting enum dispatch — so the compiler aborts rather than emit miscompiling code.

Source

Thrown at compiler/rustc_abi/src/layout.rs:860

        size = size.align_to(align);

        // FIXME(oli-obk): deduplicate and harden these checks
        if size.bytes() >= dl.obj_size_bound() {
            return Err(LayoutCalculatorError::SizeOverflow);
        }

        let typeck_ity = Integer::from_attr(dl, repr.discr_type());
        if typeck_ity < min_ity {
            // It is a bug if Layout decided on a greater discriminant size than typeck for
            // some reason at this point (based on values discriminant can take on). Mostly
            // because this discriminant will be loaded, and then stored into variable of
            // type calculated by typeck. Consider such case (a bug): typeck decided on
            // byte-sized discriminant, but layout thinks we need a 16-bit to store all
            // discriminant values. That would be a bug, because then, in codegen, in order
            // to store this 16-bit discriminant into 8-bit sized temporary some of the
            // space necessary to represent would have to be discarded (or layout is wrong
            // on thinking it needs 16 bits)
            panic!(
                "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})"
            );
            // However, it is fine to make discr type however large (as an optimisation)
            // after this point – we’ll just truncate the value we load in codegen.
        }

        // Check to see if we should use a different type for the
        // discriminant. We can safely use a type with the same size
        // as the alignment of the first field of each variant.
        // We increase the size of the discriminant to avoid LLVM copying
        // padding when it doesn't need to. This normally causes unaligned
        // load/stores and excessive memcpy/memset operations. By using a
        // bigger integer size, LLVM can be sure about its contents and
        // won't be so conservative.

        // Use the initial field alignment
        let mut ity = if repr.c() || repr.int.is_some() {
            min_ity

View on GitHub (pinned to 22057b88b0)

Solutions

  1. If you hit this on unmodified stock rustc, file an ICE at https://github.com/rust-lang/rust/issues with -Zprint-type-sizes output and a minimized enum repro.
  2. If developing the compiler, confirm Integer::from_attr(dl, repr.discr_type()) and the min_ity loop in layout_of_enum agree on width for the failing enum.
  3. Temporarily widen or remove the enum's repr(int) annotation to confirm the mismatch originates in the repr-to-integer mapping.

Example fix

// before: from_attr and layout disagree on discriminant width
#[repr(u8)]
enum E { A = 200, B = 300 } // typeck should reject; ICE if not

// fix: choose a repr wide enough for every discriminant value
#[repr(u16)]
enum E { A = 200, B = 300 }
Defensive patterns

Strategy: try-catch

Try / catch

// Layout-vs-typeck discriminant mismatch is a compiler-internal bug; the only
// user-side defense is to isolate layout computation behind catch_unwind.
use rustc_abi::LayoutCalculatorError;

let layout = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    // the call that can panic, e.g.:
    // layout_calculator.layout_of(cx, ty)
    compute_enum_layout(ty)
})) {
    Ok(Ok(l)) => l,                       // normal success
    Ok(Err(LayoutCalculatorError::SizeOverflow)) => {
        // a real, expected recoverable error returned by the API
        return Err(LayoutError::SizeOverflow);
    }
    Err(panic_payload) => {
        // errorIndex 10 lands here: bug in rustc, not user input.
        log::error!("rustc bug: discriminant layout > typeck layout: {panic_payload:?}");
        return Err(LayoutError::InternalBug);
    }
};

Prevention

When it happens

Trigger: Compiling an enum whose discriminant value range, after layout's exhaustive/niche analysis, requires a wider integer than Integer::from_attr(dl, repr.discr_type()) returns — e.g. a #[repr(u8)] enum whose values cannot be held in 8 bits once layout re-derives the minimum type. In practice only reachable if the from_attr and min_ity computations disagree, since typeck normally rejects too-small repr types first.

Common situations: Almost exclusively a compiler-developer ICE when modifying discriminant logic, merging a bad change to Integer::from_attr, or running an exotic target data layout where the integer resolution differs. Stock user code cannot reach it because typeck gates repr sizes beforehand.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/79603b6e96f6ed8c.json. Report an issue: GitHub.