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

  1. Find the caller passing the unexpected `BinaryOp` (search for `.additive_operation(` and check the op).
  2. Route multiplication/division/modulo through `multiplicative_operation` instead, which selects `__muloti4`/`__udivti3`/etc.
  3. 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

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


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