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
- 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`.
- Run `rustc` with `-Zprint-layout` / `RUSTC_LOG` to dump the offending type's layout before the panic.
- If you maintain a custom `TyAbiInterface` impl, validate that `fields` is consistent with `backend_repr` before returning a layout.
- 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
- FieldsShape::Primitive means the type has no addressable fields; never feed such a layout into a field-walking algorithm.
- Before calling layout.field(cx, i) in a loop, gate on the FieldsShape variant — Primitive layouts have no field index space.
- If you synthesize LayoutData yourself (e.g. for a foreign type), never pair BackendRepr::Memory-sized with FieldsShape::Primitive; that combination is contradictory and will trip this panic in any consumer.
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
- unsupported integer: {self:?}
- unsupported float: {self:?}
- `homogeneous_aggregate` should not be called for scalable ve
- unreachable: invalid ExternAbi variant
- assignment does not match variant
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/733063913c2e6907.json.
Report an issue: GitHub.