diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index ac000b1bb566f..a90582fc33820 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -130,7 +130,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let signed = left_layout.abi.is_signed(); let size = u128::from(left_layout.size.bits()); let overflow = r >= size; - let r = r % size; // mask to type size + // The shift offset is implicitly masked to the type size, to make sure this operation + // is always defined. This is the one MIR operator that does *not* directly map to a + // single LLVM operation. See + // + // for the corresponding truncation in our codegen backends. + let r = r % size; let r = u32::try_from(r).unwrap(); // we masked so this will always fit let result = if signed { let l = self.sign_extend(l, left_layout) as i128; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 253ac266bedaa..4210e07d2780b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2246,8 +2246,12 @@ pub enum BinOp { /// The `*` operator (multiplication) Mul, /// The `/` operator (division) + /// + /// Division by zero is UB. Div, /// The `%` operator (modulus) + /// + /// Using zero as the modulus (second operand) is UB. Rem, /// The `^` operator (bitwise xor) BitXor, @@ -2256,8 +2260,12 @@ pub enum BinOp { /// The `|` operator (bitwise or) BitOr, /// The `<<` operator (shift left) + /// + /// The offset is truncated to the size of the first operand before shifting. Shl, /// The `>>` operator (shift right) + /// + /// The offset is truncated to the size of the first operand before shifting. Shr, /// The `==` operator (equality) Eq,