rust-lang/rust · error
unexpected additive operation {:?}
Error message
unexpected additive operation {:?} What it means
In `Builder::additive_operation` the match over `(operation, signed)` only arms `BinaryOp::Plus` and `BinaryOp::Minus` (dispatched to `__rust_i128_add`/`__rust_u128_add`/`__rust_i128_sub`/`__rust_u128_sub`). Any other `BinaryOp` reaching this branch (e.g. `Mult`, `Divide`, `Modulo`, or a bitwise op) trips `unreachable!`.
Source
Thrown at compiler/rustc_codegen_gcc/src/int.rs:187
if a_type.is_vector() {
// Vector types need to be bitcast.
// FIXME(antoyo): perhaps use __builtin_convertvector for vector casting.
b = self.context.new_bitcast(self.location, b, a_type);
} else {
b = self.context.new_cast(self.location, b, a_type);
}
}
self.context.new_binary_op(self.location, operation, a_type, a, b)
} else {
debug_assert!(a_type.dyncast_array().is_some());
debug_assert!(b_type.dyncast_array().is_some());
let signed = a_type.is_compatible_with(self.i128_type);
let func_name = match (operation, signed) {
(BinaryOp::Plus, true) => "__rust_i128_add",
(BinaryOp::Plus, false) => "__rust_u128_add",
(BinaryOp::Minus, true) => "__rust_i128_sub",
(BinaryOp::Minus, false) => "__rust_u128_sub",
_ => unreachable!("unexpected additive operation {:?}", operation),
};
let param_a = self.context.new_parameter(self.location, a_type, "a");
let param_b = self.context.new_parameter(self.location, b_type, "b");
let func = self.context.new_function(
self.location,
FunctionType::Extern,
a_type,
&[param_a, param_b],
func_name,
false,
);
self.context.new_call(self.location, func, &[a, b])
}
}
pub fn gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
self.additive_operation(BinaryOp::Plus, a, b)
}View on GitHub (pinned to 22057b88b0)
Solutions
- Find the caller passing the unexpected `BinaryOp` (search for `.additive_operation(` and check the op).
- Route multiplication/division/modulo through `multiplicative_operation` instead, which selects `__muloti4`/`__udivti3`/etc.
- If you genuinely need a new additive op, add an arm mapping it to the correct `__rust_i128_*`/`__rust_u128_*` runtime symbol.
Example fix
// before
let func_name = match (operation, signed) {
(BinaryOp::Plus, true) => "__rust_i128_add",
(BinaryOp::Plus, false) => "__rust_u128_add",
(BinaryOp::Minus, true) => "__rust_i128_sub",
(BinaryOp::Minus, false) => "__rust_u128_sub",
_ => unreachable!("unexpected additive operation {:?}", operation),
};
// after (defensive: route multiplicative ops to the right helper, fail loudly otherwise)
let func_name = match (operation, signed) {
(BinaryOp::Plus, true) => "__rust_i128_add",
(BinaryOp::Plus, false) => "__rust_u128_add",
(BinaryOp::Minus, true) => "__rust_i128_sub",
(BinaryOp::Minus, false) => "__rust_u128_sub",
other => panic!("additive_operation called with non-additive op {:?}; use multiplicative_operation", other),
}; Defensive patterns
Strategy: validation
Validate before calling
// additive_operation only supports BinaryOp::Plus and BinaryOp::Minus.
// Validate before dispatching a BinaryOp into it.
use gccjit::BinaryOp;
fn is_additive(op: BinaryOp) -> bool {
matches!(op, BinaryOp::Plus | BinaryOp::Minus)
}
if !is_additive(operation) {
return Err(format!("additive_operation: unsupported op {:?}; use gcc_mul/gcc_sdiv instead", operation));
}
builder.additive_operation(operation, a, b) Prevention
- additive_operation is a private dispatcher; always enter it through the public gcc_add (Plus) and gcc_sub (Minus) wrappers, never with Mult/Divide/Modulo.
- If you extend the backend with a new BinaryOp, update the match arms in additive_operation at the same time rather than relying on the unreachable fallback.
- Treat the unreachable! as a hard contract: Plus/Minus only. Add a debug_assert!(is_additive(operation)) at the call site during development.
When it happens
Trigger: `additive_operation` is called (via `gcc_add`/`gcc_sub`) but with a `BinaryOp` other than `Plus`/`Minus`, while the operands are non-native 128-bit integers. The public API (`gcc_add`, `gcc_sub`) only ever passes `Plus`/`Minus`, so this fires only when an internal caller is wired to the wrong helper — e.g. someone routing `gcc_mul` through `additive_operation` by mistake.
Common situations: A regression in a refactor that moves multiplicative ops into `additive_operation`, or a custom fork that added a new BinaryOp variant without extending the match. Not user-facing in stock rustc — purely an internal-invariant violation.
Related errors
- element type
- get element type
- internal error: entered unreachable code
- non-array a value
- unexpected integer size
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/de430bee90fb28ec.json.
Report an issue: GitHub.