{"id":"6e87b4922059bfd4","repo":"rust-lang/rust","slug":"expected-multi-variant-layout-in-layout-for-vari","errorCode":null,"errorMessage":"Expected multi-variant layout in `Layout::for_variant`","messagePattern":"Expected multi-variant layout in `Layout::for_variant`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_abi/src/layout/simple.rs","lineNumber":156,"sourceCode":"            },\n            backend_repr: BackendRepr::Memory { sized: true },\n            largest_niche: None,\n            uninhabited: true,\n            align: AbiAlign::new(dl.i8_align),\n            size: Size::ZERO,\n            max_repr_align: None,\n            unadjusted_abi_align: dl.i8_align,\n            // Variant layouts never flow back into actual layout computations,\n            // so dummy values are fine here.\n            randomization_seed: Hash64::ZERO,\n        }\n    }\n\n    /// Returns a layout for an inhabited variant.\n    pub fn for_variant(parent: &Self, index: VariantIdx) -> Self {\n        let layout = match &parent.variants {\n            Variants::Multiple { variants, .. } => &variants[index],\n            _ => panic!(\"Expected multi-variant layout in `Layout::for_variant`\"),\n        };\n\n        Self {\n            fields: FieldsShape::Arbitrary {\n                offsets: layout.field_offsets.clone(),\n                in_memory_order: layout.fields_in_memory_order.clone(),\n            },\n            variants: Variants::Single { index },\n            backend_repr: layout.backend_repr,\n            largest_niche: layout.largest_niche,\n            uninhabited: layout.uninhabited,\n            size: layout.size,\n            align: parent.align,\n            max_repr_align: parent.max_repr_align,\n            unadjusted_abi_align: parent.unadjusted_abi_align,\n            // Variant layouts never flow back into actual layout computations,\n            // so dummy values are fine here.\n            randomization_seed: Hash64::ZERO,","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_abi/src/layout/simple.rs#L138-L174","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet v = Layout::for_variant(&parent, idx); // panics if parent is Single/Empty\n\n// after\nlet v = match &parent.variants {\n    Variants::Multiple { variants, .. } => variants[idx].clone(),\n    Variants::Single { .. } => parent.clone(),\n    Variants::Empty => parent.clone(),\n};","handlingStrategy":"type-guard","validationCode":"// Layout::for_variant panics unless the parent layout is Variants::Multiple.\nuse rustc_abi::{Layout, LayoutData, Variants};\nfn can_project_variant<F, V>(layout: &LayoutData<F, V>) -> bool {\n    matches!(layout.variants, Variants::Multiple { .. })\n}\n// caller:\n// if can_project_variant(&parent) { Layout::for_variant(&parent, idx) } else { /* parent is single-variant; idx must be 0 or the layout itself */ }","typeGuard":"fn is_multi_variant_layout<F, V>(layout: &LayoutData<F, V>) -> bool {\n    matches!(layout.variants, Variants::Multiple { .. })\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    Layout::for_variant(&parent, variant_idx)\n}));\nmatch result {\n    Ok(v) => { /* projected variant layout */ }\n    Err(_) => {\n        // parent is Variants::Single; the only legal variant index is its own index.\n        // Fall back to returning the parent layout unchanged.\n    }\n}","preventionTips":["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."],"tags":["rustc","enum","layout","variant","ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}