rust-lang/rust · critical

aggregates can't have `FieldsShape::Primitive`

Error message

aggregates can't have `FieldsShape::Primitive`

What it means

While computing whether a memory-sized or scalar-pair aggregate is homogeneous, the walker matches on `layout.fields`. `FieldsShape::Primitive` is reserved for types whose layout is a bare primitive (scalars) and which therefore never enter the aggregate-walking branch — by the time the code reaches this match the type is `ScalarPair` or `Memory { sized: true }`, which must have Array/Union/Arbitrary fields. Seeing `Primitive` here means the layout was built inconsistently.

Source

Thrown at compiler/rustc_abi/src/callconv.rs:101

                    kind: RegKind::Vector { hint_vector_elem: element.primitive() },
                    size: self.size,
                }))
            }

            BackendRepr::SimdScalableVector { .. } => {
                unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
            }

            BackendRepr::ScalarPair { .. } | BackendRepr::Memory { sized: true } => {
                // Helper for computing `homogeneous_aggregate`, allowing a custom
                // starting offset (used below for handling variants).
                let from_fields_at =
                    |layout: Self,
                     start: Size|
                     -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
                        let is_union = match layout.fields {
                            FieldsShape::Primitive => {
                                unreachable!("aggregates can't have `FieldsShape::Primitive`")
                            }
                            FieldsShape::Array { count, .. } => {
                                assert_eq!(start, Size::ZERO);

                                let result = if count > 0 {
                                    layout.field(cx, 0).homogeneous_aggregate(cx)?
                                } else {
                                    HomogeneousAggregate::NoData
                                };
                                return Ok((result, layout.size));
                            }
                            FieldsShape::Union(_) => true,
                            FieldsShape::Arbitrary { .. } => false,
                        };

                        let mut result = HomogeneousAggregate::NoData;
                        let mut total = start;

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Find where the `LayoutData` was assembled (search for `FieldsShape::Primitive` producers) and ensure scalar types keep `Scalar` repr while real aggregates get `Array`/`Union`/`Arbitrary`.
  2. Run `rustc` with `-Zprint-layout` / `RUSTC_LOG` to dump the offending type's layout before the panic.
  3. If you maintain a custom `TyAbiInterface` impl, validate that `fields` is consistent with `backend_repr` before returning a layout.
  4. File an ICE with the type definition that triggers it.

Example fix

// before
LayoutData {
    backend_repr: BackendRepr::Memory { sized: true },
    fields: FieldsShape::Primitive, // inconsistent — panics in homogeneous_aggregate
    ..
}

// after
LayoutData {
    backend_repr: BackendRepr::Memory { sized: true },
    fields: FieldsShape::Arbitrary { offsets, in_memory_order },
    ..
}
Defensive patterns

Strategy: validation

Validate before calling

// homogeneous_aggregate unreachable!() when an aggregate's FieldsShape is Primitive.
use rustc_abi::{FieldsShape, LayoutData};
fn aggregate_has_real_fields<F, V>(layout: &LayoutData<F, V>) -> bool {
    !matches!(layout.fields, FieldsShape::Primitive)
}
// caller: assert/branch on aggregate_has_real_fields before computing field offsets
// for a memory/union/array/scalar-pair layout.

Type guard

fn is_fielded_aggregate<F, V>(layout: &LayoutData<F, V>) -> bool {
    matches!(
        layout.fields,
        FieldsShape::Union(_) | FieldsShape::Array { .. } | FieldsShape::Arbitrary { .. }
    )
}

Try / catch

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    /* the field-walking homogeneous_aggregate inner closure */
}));
if result.is_err() {
    // A Primitive FieldsShape was handed to aggregate logic; recover by treating
    // the value as a single opaque scalar instead of recursing into 'fields'.
}

Prevention

When it happens

Trigger: `homogeneous_aggregate` reaching `from_fields_at` for a `BackendRepr::ScalarPair` or `BackendRepr::Memory { sized: true }` type whose `fields` shape is `FieldsShape::Primitive` — a state that should be impossible given how `LayoutData` is constructed.

Common situations: An internal layout-computation bug that produced a `Memory`/`ScalarPair` `BackendRepr` together with a `FieldsShape::Primitive`, a hand-constructed `LayoutData` in a codegen backend or test harness that mixes the two, or a refactor that stopped upgrading a primitive-shaped type to a real aggregate shape.

Related errors


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