rust-lang/rust · error
get element type
Error message
get element type
What it means
Raised inside the fallback branch of `Builder::gcc_lshr` (logical right-shift) for non-native integer operands. When neither `a` nor `b` is a native int and the vector-of-two-vectors path does not apply, the code assumes the operand type is an i128/u128 represented as a two-element array and calls `dyncast_array()` to recover the element (i64/u64) type. A `None` result means a non-array type reached this branch.
Source
Thrown at compiler/rustc_codegen_gcc/src/int.rs:104
std::cmp::Ordering::Equal => a >> b,
_ => {
// NOTE: it is OK to cast even if b has a type bigger than a because b has
// been masked by codegen_ssa before calling Builder::lshr or
// Builder::ashr.
let b = self.context.new_cast(self.location, b, a_type);
a >> b
}
}
}
} else if a_type.is_vector() && b_type.is_vector() {
a >> b
} else if a_native && !b_native {
self.gcc_lshr(a, self.gcc_int_cast(b, a_type))
} else {
// NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most
// significant half of the number) which uses lshr.
let native_int_type = a_type.dyncast_array().expect("get element type");
let func = self.current_func();
let then_block = func.new_block("then");
let else_block = func.new_block("else");
let after_block = func.new_block("after");
let b0_block = func.new_block("b0");
let actual_else_block = func.new_block("actual_else");
let result = func.new_local(self.location, a_type, "shiftResult");
let sixty_four = self.gcc_int(native_int_type, 64);
let sixty_three = self.gcc_int(native_int_type, 63);
let zero = self.gcc_zero(native_int_type);
let b = self.gcc_int_cast(b, native_int_type);
let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
self.llbb().end_with_conditional(self.location, condition, then_block, else_block);
let shift_value = self.gcc_sub(b, sixty_four);View on GitHub (pinned to 22057b88b0)
Solutions
- Add an `eprintln!` of `a_type` (and `{:?}`) at the entry to the non-native branch to identify the unexpected type.
- Audit callers of `gcc_lshr` in the codegen SSA layer to ensure `b` is always cast to `a_type` (or a native int) before this point.
- Re-check `is_native_int_type` / `is_non_native_int_type` helpers for the target's pointer width — an i128 on a 64-bit target should be native.
- Confirm libgccjit version: the array-of-two representation is a workaround and is sensitive to libgccjit's handling of 128-bit integers.
Example fix
// before
let native_int_type = a_type.dyncast_array().expect("get element type");
// after
let native_int_type = a_type.dyncast_array().unwrap_or_else(|| {
panic!("gcc_lshr: non-native operand is not an i128 array: {:?}", a_type);
}); Defensive patterns
Strategy: type-guard
Validate before calling
// gcc_lshr's emulation branch needs a_type.dyncast_array(). Reject mixed
// native/non-native operand pairs before shifting.
let a_type = a.get_type();
let b_type = b.get_type();
let a_native = builder.is_native_int_type(a_type);
let b_native = builder.is_native_int_type(b_type);
if !a_native && a_type.dyncast_array().is_none() {
return Err("lshr: left operand is neither native int nor an array type");
}
if a_native != b_native && !(a_type.is_vector() && b_type.is_vector()) {
// cast b to a's native type first to stay on the native shift path
let b = builder.gcc_int_cast(b, a_type);
} Type guard
/// True when a >> b can take the gcc_lshr native/vector path without
/// falling into the dyncast_array emulation branch.
fn is_safe_lshr_pair<'gcc>(
&self,
a_type: gccjit::Type<'gcc>,
b_type: gccjit::Type<'gcc>,
) -> bool {
let a_native = self.is_native_int_type(a_type);
let b_native = self.is_native_int_type(b_type);
(a_native && b_native)
|| (a_type.is_vector() && b_type.is_vector())
|| (a_native && !b_native)
|| a_type.dyncast_array().is_some() // emulation branch is valid for arrays
} Prevention
- Keep both shift operands the same signedness and width so gcc_lshr stays on the native path and never reaches the dyncast_array fallback.
- Mask the shift amount (b & (width-1)) at the SSA layer before codegen, as codegen_ssa already does; a stray unmasked b on a non-native type forces the array path.
- Avoid logical-right-shifting a value whose type the backend reports as non-native but cannot dyncast to an array (mis-built 128-bit value).
When it happens
Trigger: `Builder::gcc_lshr(a, b)` is invoked with `a_type` failing `is_native_int_type`, `a_type.is_vector()` false, `b` non-native, and `a_type.dyncast_array()` returning `None`. Typically hit when shifting a 128-bit value on a target where the type is not actually materialized as a 2-element array.
Common situations: ICE during codegen of `>>` on i128/u128 on a 32-bit target, after upgrading libgccjit (array representation may have changed), or after a bug in `TypeReflection::is_non_native_int_type` mislabels a non-int (e.g. a pointer or aggregate) as a non-native int.
Related errors
- element type
- non-array a value
- unexpected additive operation {:?}
- internal error: entered unreachable code
- unexpected integer size
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/29c53c7fd66c5a20.json.
Report an issue: GitHub.