rust-lang/rust · critical
Expected multi-variant layout in `Layout::for_variant`
Error message
Expected multi-variant layout in `Layout::for_variant`
What it means
`Layout::for_variant(parent, index)` extracts one variant's layout out of a multi-variant enum. It only knows how to read variant data from `Variants::Multiple { variants, .. }`; a `Variants::Single` or `Variants::Empty` parent has no variant table to index. Asking 'give me variant N' of a layout that doesn't have multiple variants is a misuse.
Source
Thrown at compiler/rustc_abi/src/layout/simple.rs:156
},
backend_repr: BackendRepr::Memory { sized: true },
largest_niche: None,
uninhabited: true,
align: AbiAlign::new(dl.i8_align),
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: dl.i8_align,
// Variant layouts never flow back into actual layout computations,
// so dummy values are fine here.
randomization_seed: Hash64::ZERO,
}
}
/// Returns a layout for an inhabited variant.
pub fn for_variant(parent: &Self, index: VariantIdx) -> Self {
let layout = match &parent.variants {
Variants::Multiple { variants, .. } => &variants[index],
_ => panic!("Expected multi-variant layout in `Layout::for_variant`"),
};
Self {
fields: FieldsShape::Arbitrary {
offsets: layout.field_offsets.clone(),
in_memory_order: layout.fields_in_memory_order.clone(),
},
variants: Variants::Single { index },
backend_repr: layout.backend_repr,
largest_niche: layout.largest_niche,
uninhabited: layout.uninhabited,
size: layout.size,
align: parent.align,
max_repr_align: parent.max_repr_align,
unadjusted_abi_align: parent.unadjusted_abi_align,
// Variant layouts never flow back into actual layout computations,
// so dummy values are fine here.
randomization_seed: Hash64::ZERO,View on GitHub (pinned to 22057b88b0)
Solutions
- Before calling `for_variant`, check `matches!(parent.variants, Variants::Multiple { .. })`; for `Single { index }` the variant is the layout itself, for `Empty` there are no variants.
- Use the existing `TyAndLayout` helpers that already gate on `variants`, rather than reaching into `Layout::for_variant` directly.
- If you maintain a layout cache, key it by `(type, Option<VariantIdx>)` so single-variant types never ask for a variant.
- Add a debug-assertion upstream that catches single-variant parents before they reach this point.
Example fix
// before
let v = Layout::for_variant(&parent, idx); // panics if parent is Single/Empty
// after
let v = match &parent.variants {
Variants::Multiple { variants, .. } => variants[idx].clone(),
Variants::Single { .. } => parent.clone(),
Variants::Empty => parent.clone(),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Layout::for_variant panics unless the parent layout is Variants::Multiple.
use rustc_abi::{Layout, LayoutData, Variants};
fn can_project_variant<F, V>(layout: &LayoutData<F, V>) -> bool {
matches!(layout.variants, Variants::Multiple { .. })
}
// caller:
// if can_project_variant(&parent) { Layout::for_variant(&parent, idx) } else { /* parent is single-variant; idx must be 0 or the layout itself */ } Type guard
fn is_multi_variant_layout<F, V>(layout: &LayoutData<F, V>) -> bool {
matches!(layout.variants, Variants::Multiple { .. })
} Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
Layout::for_variant(&parent, variant_idx)
}));
match result {
Ok(v) => { /* projected variant layout */ }
Err(_) => {
// parent is Variants::Single; the only legal variant index is its own index.
// Fall back to returning the parent layout unchanged.
}
} Prevention
- Only call for_variant on layouts you have confirmed are multi-variant (enums/coroutines with >=2 variants); for Variants::Single the layout already describes the sole inhabitant.
- When you receive a Layout from an opaque source, narrow on Variants first rather than assuming the discriminator domain is non-trivial.
- Remember that niche-optimized enums collapse to Variants::Single { index } when only one variant is actually inhabited — guard for that even if the source enum textually has many variants.
When it happens
Trigger: Calling `Layout::for_variant(&parent_layout, index)` when `parent_layout.variants` is `Variants::Single { .. }` or `Variants::Empty` — i.e. the type is not a multi-variant enum but the caller assumed it was.
Common situations: A codegen/MIR path that treats every type as a potential enum and calls `for_variant` unconditionally, a refactor that changed a type's layout from multi-variant to single-variant without updating the caller, or a query that caches a single-variant layout being fed into a variant-aware consumer.
Related errors
- a multi-variant layout should have `Arbitrary` fields
- aggregates can't have `FieldsShape::Primitive`
- assignment does not match variant
- layout decided on a larger discriminant type ({min_ity:?}) t
- encountered a non-arbitrary layout during enum layout
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/6e87b4922059bfd4.json.
Report an issue: GitHub.