about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-02-09 15:41:40 +0100
committerRalf Jung <post@ralfj.de>2020-02-09 15:41:54 +0100
commit28f85c6ffad77554150e7cab4ccac38b26621bdb (patch)
tree832043532309caf3ae721c2b6cd129de8378281a
parent202d401c2504f17133c50505b82fe4278ab2c842 (diff)
downloadrust-28f85c6ffad77554150e7cab4ccac38b26621bdb.tar.gz
rust-28f85c6ffad77554150e7cab4ccac38b26621bdb.zip
bring back extra check for int_min%-1
-rw-r--r--src/librustc_mir/interpret/operator.rs11
1 files changed, 11 insertions, 0 deletions
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index b4f6b5f8999..abe437bd8d7 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -195,6 +195,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if let Some(op) = op {
                 let l128 = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
+                // We need a special check for overflowing remainder:
+                // "int_min % -1" overflows and returns 0, but after casting things to a larger int
+                // type it does *not* overflow nor give an unrepresentable result!
+                match bin_op {
+                    Rem => {
+                        if r == -1 && l == (1 << (size.bits() - 1)) {
+                            return Ok((Scalar::from_int(0, size), true, left_layout.ty));
+                        }
+                    }
+                    _ => {}
+                }
 
                 let (result, oflo) = op(l128, r);
                 // This may be out-of-bounds for the result type, so we have to truncate ourselves.