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() > 0

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Before calling `VariantLayout::from_layout`, ensure the variant's fields were passed through the layout pass that produces `FieldsShape::Arbitrary` (struct-like offset assignment).
  2. 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.
  3. 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

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


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