rust-lang/rust · critical
Layout of fields should be Arbitrary for variants
Error message
Layout of fields should be Arbitrary for variants
What it means
Thrown by `VariantLayout::from_layout` at compiler/rustc_abi/src/lib.rs:2390. An enum variant must lay out its fields with explicit offsets, i.e. `FieldsShape::Arbitrary`. The constructor destructures the layout assuming `Arbitrary { offsets, in_memory_order }`; any other `FieldsShape` (`Primitive`, `Union`, `Array`) is structurally incompatible with how variants are represented, so building a `VariantLayout` from one is a logic error.
Source
Thrown at compiler/rustc_abi/src/lib.rs:2390
NoExplicitUnwind,
}
// NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(StableHash))]
pub struct VariantLayout<FieldIdx: Idx> {
pub size: Size,
pub backend_repr: BackendRepr,
pub field_offsets: IndexVec<FieldIdx, Size>,
fields_in_memory_order: IndexVec<u32, FieldIdx>,
largest_niche: Option<Niche>,
uninhabited: bool,
}
impl<FieldIdx: Idx> VariantLayout<FieldIdx> {
pub fn from_layout(layout: LayoutData<FieldIdx, impl Idx>) -> Self {
let FieldsShape::Arbitrary { offsets, in_memory_order } = layout.fields else {
panic!("Layout of fields should be Arbitrary for variants");
};
Self {
size: layout.size,
backend_repr: layout.backend_repr,
field_offsets: offsets,
fields_in_memory_order: in_memory_order,
largest_niche: layout.largest_niche,
uninhabited: layout.uninhabited,
}
}
pub fn is_uninhabited(&self) -> bool {
self.uninhabited
}
pub fn has_fields(&self) -> bool {
self.field_offsets.len() > 0View on GitHub (pinned to 22057b88b0)
Solutions
- Before calling `VariantLayout::from_layout`, ensure the variant's fields were passed through the layout pass that produces `FieldsShape::Arbitrary` (struct-like offset assignment).
- Add a debug assertion / pattern check on `layout.fields` upstream of this call so a mis-shaped layout is caught where it is produced, not where it is consumed.
- If the layout genuinely cannot be `Arbitrary` (e.g. a zero-field unit-like variant), special-case it before reaching `from_layout` rather than forcing a `Union`/`Primitive` shape through.
Example fix
// before
let variant = VariantLayout::from_layout(layout);
// after
let FieldsShape::Arbitrary { offsets, in_memory_order } = &layout.fields else {
bug!("variant {variant_idx:?} got non-Arbitrary field shape {:?}", layout.fields);
};
// ...or ensure the layout calculator always assigns Arbitrary to variants. Defensive patterns
Strategy: type-guard
Validate before calling
// VariantLayout::from_layout requires FieldsShape::Arbitrary. Match first.
fn try_variant_layout<FieldIdx: rustc_index::Idx>(
layout: rustc_abi::LayoutData<FieldIdx, impl rustc_index::Idx>,
) -> Result<rustc_abi::VariantLayout<FieldIdx>, &'static str> {
match &layout.fields {
rustc_abi::FieldsShape::Arbitrary { .. } =>
Ok(rustc_abi::VariantLayout::from_layout(layout)),
_ => Err("VariantLayout requires FieldsShape::Arbitrary"),
}
} Type guard
fn fields_are_arbitrary<FieldIdx: rustc_index::Idx>(
layout: &rustc_abi::LayoutData<FieldIdx, impl rustc_index::Idx>,
) -> bool {
matches!(layout.fields, rustc_abi::FieldsShape::Arbitrary { .. })
} Try / catch
// Panic by design; converting it to a Result via the wrapper above is the // recommended pattern. Do not rely on catch_unwind.
Prevention
- Variants only make sense when each field has its own offset (Arbitrary); Union/Array/Primitive shapes cannot back a variant.
- Before calling VariantLayout::from_layout, ensure the LayoutData was produced by the layouter for an enum/struct, not an array or union.
- If you accept LayoutData from an external source, validate the FieldsShape variant in the same match you validate size/align.
When it happens
Trigger: Passing a `LayoutData` whose `fields` is not `FieldsShape::Arbitrary` into `VariantLayout::from_layout`. This occurs when a caller reuses a single struct/array layout path to construct variant layouts, or when a layout-calculator bug assigns a non-`Arbitrary` shape to a variant.
Common situations: Wrong code path in a layout engine that handles structs and enum variants together without separating them; rust-analyzer or miri replaying layouts they constructed themselves; or a refactor that stopped running the variant-specific field-shape assignment (the pass that converts a variant's fields into `Arbitrary { offsets, in_memory_order }`).
Related errors
- Size::bits: {bytes} bytes in bits doesn't fit in u64
- Size::add: {} + {} doesn't fit in u64
- Size::sub: {} - {} would result in negative size
- Size::mul: {} * {} doesn't fit in u64
- cannot change the valid range of a union
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/8cc68f6dbfca5fc8.json.
Report an issue: GitHub.