{"id":"7b207dbc7576f2aa","repo":"rust-lang/rust","slug":"a-multi-variant-layout-should-have-arbitrary-fie","errorCode":null,"errorMessage":"a multi-variant layout should have `Arbitrary` fields","messagePattern":"a multi-variant layout should have `Arbitrary` fields","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_abi/src/layout/ty.rs","lineNumber":364,"sourceCode":"        variant_index: VariantIdx,\n    ) -> Vec<Range<Size>>\n    where\n        Ty: TyAbiInterface<'a, C> + Copy,\n    {\n        let Variants::Multiple { .. } = self.variants else {\n            return Vec::new();\n        };\n\n        // Bytes that are data in some variant.\n        let mut any = RangeSet::new();\n        self.add_data_ranges(cx, Size::ZERO, &mut any);\n\n        // Bytes that are data in this variant.\n        let mut this = RangeSet::new();\n\n        // The variants do not contain e.g. the discriminant or coroutine upvars.\n        let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {\n            unreachable!(\"a multi-variant layout should have `Arbitrary` fields\")\n        };\n\n        // So add them explicitly.\n        for (field, &offset) in offsets.iter_enumerated() {\n            let field = self.field(cx, field.as_usize());\n            field.add_data_ranges(cx, offset, &mut this);\n        }\n\n        self.for_variant(cx, variant_index).add_data_ranges(cx, Size::ZERO, &mut this);\n\n        // Padding specific to this variant: data in some variant, but not in this one.\n        any.difference(&this).0.iter().map(|&(offset, size)| offset..offset + size).collect()\n    }\n\n    /// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type.\n    /// For enums and unions there are offsets that are initialized for some\n    /// variants but not for others; those offset *will* get added to `out`.\n    fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>)","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_abi/src/layout/ty.rs#L346-L382","documentation":"`variant_dependent_padding_ranges` computes which bytes are padding for a specific enum variant. Multi-variant layouts always store per-variant field offsets in a `FieldsShape::Arbitrary` (offsets + in_memory_order); other shapes (Primitive/Array/Union) cannot express per-variant fields, so reaching this code with a non-Arbitrary multi-variant layout means the layout is internally inconsistent.","triggerScenarios":"Calling `variant_dependent_padding_ranges(cx, variant_index)` on a `TyAndLayout` whose `variants` is `Variants::Multiple` but whose `fields` is not `FieldsShape::Arbitrary` — a state that the layout builder is supposed to prevent.","commonSituations":"A layout-computation change that built a multi-variant enum with the wrong field shape, a custom `TyAbiInterface` impl returning an inconsistent `LayoutData`, or corruption of a cached layout. Real enums never hit this; only a builder bug does.","solutions":["Find the layout builder for enums (the `Variants::Multiple` arm of the layout calculator) and confirm it always emits `FieldsShape::Arbitrary` with per-variant offsets.","Validate `LayoutData` invariants in your `TyAbiInterface` impl before returning: multi-variant ⇒ Arbitrary fields.","Dump the layout with `-Zprint-layout` to confirm the offending type, then check the repr/options that produced it.","File an ICE with the enum definition if it reproduces on stock rustc."],"exampleFix":"// before — multi-variant enum built with a non-Arbitrary field shape\nLayoutData {\n    variants: Variants::Multiple { .. },\n    fields: FieldsShape::Primitive, // inconsistent; later panics\n    ..\n}\n\n// after\nLayoutData {\n    variants: Variants::Multiple { tag, variants, tag_encoding },\n    fields: FieldsShape::Arbitrary { offsets, in_memory_order },\n    ..\n}","handlingStrategy":"validation","validationCode":"// variant_dependent_padding_ranges asserts a multi-variant layout must have\n// FieldsShape::Arbitrary. Validate both conditions up front.\nuse rustc_abi::{FieldsShape, LayoutData, Variants};\nfn safe_padding_query<F, V>(layout: &LayoutData<F, V>) -> bool {\n    matches!(layout.variants, Variants::Multiple { .. })\n        && matches!(layout.fields, FieldsShape::Arbitrary { .. })\n}\n// caller:\n// if safe_padding_query(&layout) { layout.variant_dependent_padding_ranges(cx, idx) } else { Vec::new() }","typeGuard":"fn has_arbitrary_field_shape<F, V>(layout: &LayoutData<F, V>) -> bool {\n    matches!(layout.fields, FieldsShape::Arbitrary { .. })\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    layout.variant_dependent_padding_ranges(cx, variant_idx)\n}));\nmatch result {\n    Ok(ranges) => { /* use ranges */ }\n    Err(_) => {\n        // Multi-variant layout had non-Arbitrary fields (shouldn't happen for\n        // well-formed enum layouts). Return empty padding as a safe default.\n    }\n}","preventionTips":["Multi-variant layouts are always Arbitrary by construction; if you build or transform LayoutData yourself, never leave a Variants::Multiple paired with Union/Array/Primitive fields.","Treat variant_dependent_padding_ranges as callable only on enum/coroutine layouts you obtained from the layout calculator unchanged — do not call it on layouts you have patched.","If you must inspect padding on a layout you cannot fully trust, short-circuit to Vec::new() when the fields shape is not Arbitrary."],"tags":["rustc","enum","layout","padding","ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}