rust-lang/rust · error
FieldsShape::offset: `Primitive`s have no fields
Error message
FieldsShape::offset: `Primitive`s have no fields
What it means
Marked `unreachable!` at compiler/rustc_abi/src/lib.rs:1694 inside `FieldsShape::offset`. `FieldsShape::Primitive` represents scalar types and `!`, which by definition have no fields; asking for the offset of field `i` is therefore a logic error in the caller. The other variants (`Union`, `Array`, `Arbitrary`) all yield a real offset.
Source
Thrown at compiler/rustc_abi/src/lib.rs:1694
},
}
impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
#[inline]
pub fn count(&self) -> usize {
match *self {
FieldsShape::Primitive => 0,
FieldsShape::Union(count) => count.get(),
FieldsShape::Array { count, .. } => count.try_into().unwrap(),
FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
}
}
#[inline]
pub fn offset(&self, i: usize) -> Size {
match *self {
FieldsShape::Primitive => {
unreachable!("FieldsShape::offset: `Primitive`s have no fields")
}
FieldsShape::Union(count) => {
assert!(i < count.get(), "tried to access field {i} of union with {count} fields");
Size::ZERO
}
FieldsShape::Array { stride, count } => {
let i = u64::try_from(i).unwrap();
assert!(i < count, "tried to access field {i} of array with {count} fields");
stride * i
}
FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::new(i)],
}
}
/// Gets source indices of the fields by increasing offsets.
#[inline]
pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> {
// Primitives don't really have fields in the way that structs do,View on GitHub (pinned to 22057b88b0)
Solutions
- Short-circuit on `FieldsShape::Primitive` before iterating fields: `if matches!(fields, FieldsShape::Primitive) { return; }`.
- Use `fields.count()` (which returns 0 for `Primitive`) to guard the loop so no offset is ever requested.
- If you genuinely expected a fielded layout here, the upstream layout computation is wrong — the type should not have been assigned `Primitive`; investigate why `compute().backend_repr` classified it as scalar.
Example fix
// before
for i in 0..fields.count() {
let off = fields.offset(i);
...
}
// after
if matches!(fields, FieldsShape::Primitive) {
return; // scalars and ! have no fields
}
for i in 0..fields.count() {
let off = fields.offset(i);
...
} Defensive patterns
Strategy: type-guard
Validate before calling
// FieldsShape::offset panics for Primitive variants. Branch on the variant first.
fn field_offset(shape: &rustc_abi::FieldsShape, i: usize) -> Option<rustc_abi::Size> {
match shape {
rustc_abi::FieldsShape::Primitive => None,
rustc_abi::FieldsShape::Union(_) => Some(rustc_abi::Size::ZERO),
rustc_abi::FieldsShape::Array { stride, count } => {
let i = u64::try_from(i).ok()?;
(i < *count).then(|| *stride * i)
}
rustc_abi::FieldsShape::Arbitrary { offsets, .. } => Some(offsets[rustc_field_idx(i)]),
}
} Type guard
fn has_fields(shape: &rustc_abi::FieldsShape) -> bool {
!matches!(shape, rustc_abi::FieldsShape::Primitive)
} Try / catch
// unreachable! by design; do not catch. Treat reaching offset() on Primitive as // a caller bug to be fixed by the type guard above.
Prevention
- Primitives have no fields; never index into them. Track whether a layout is Primitive separately from Struct/Array/Union.
- If you hold a FieldsShape of unknown variant, always match exhaustively rather than assuming Arbitrary/Array.
- Add a debug_assert!(matches!(shape, Primitive => false, _ => true)) at the entry of any field-iteration helper.
When it happens
Trigger: Calling `fields.offset(i)` (or any consumer that iterates fields) on a layout whose `FieldsShape` is `Primitive` — i.e. a scalar or `!`-typed value. Reached when field-iteration code does not first check `matches!(fields, FieldsShape::Primitive)` or `fields.count() == 0`.
Common situations: Codegen or debug-info passes that walk fields uniformly across all types without short-circuiting scalars; rust-analyzer or other tools replaying layouts; or generic field-walking helpers shared between struct and scalar layouts.
Related errors
- cannot change the valid range of a union
- Layout of fields should be Arbitrary for variants
- 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
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/5a3a1b1a2ede1b4d.json.
Report an issue: GitHub.