about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick McCarter <p.mccarter@gmail.com>2019-02-06 18:10:08 -0500
committerPatrick McCarter <p.mccarter@gmail.com>2019-02-06 18:10:08 -0500
commitf857199073753956db92e6710f9178e34de4122e (patch)
tree02d5dad50868015a72709966368667a62d02a9e2
parentc5586ebe26eae41db94549903aa597cb0247e217 (diff)
downloadrust-f857199073753956db92e6710f9178e34de4122e.tar.gz
rust-f857199073753956db92e6710f9178e34de4122e.zip
fix saturating_sub() underflow for unsigned ints #58030
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs22
-rw-r--r--src/test/run-pass/const-int-saturating-arith.rs4
2 files changed, 15 insertions, 11 deletions
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 62a0b3d9524..827c4e62ecd 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -139,12 +139,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                             Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                         }
                     } else {
-                        if num_bits == 128 {
-                            Scalar::from_uint(u128::max_value(), Size::from_bits(128))
-                        } else {
-                            Scalar::from_uint(u128::max_value() & ((1 << num_bits) - 1),
-                                Size::from_bits(num_bits))
-                        }
+                        Scalar::from_uint(u128::max_value() >> (128 - num_bits), Size::from_bits(num_bits))
                     };
                     self.write_scalar(val, dest)?;
                 } else {
@@ -158,12 +153,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 if overflowed {
                     let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
                     let num_bits = l.layout.size.bits();
-                    let val = if first_term & (1 << (num_bits-1)) == 0 {  // first term is positive
-                        // so overflow is positive
-                        Scalar::from_uint((1u128 << (num_bits - 1)) - 1, Size::from_bits(num_bits))
+                    let val = if l.layout.abi.is_signed() {
+                        if first_term & (1 << (num_bits-1)) == 0 {  // first term is positive
+                            // so overflow is positive
+                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1, Size::from_bits(num_bits))
+                        } else {
+                            // if first term negative, overflow must be negative
+                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
+                        }
                     } else {
-                        // if first term negative, overflow must be negative
-                        Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
+                        // unsigned underflow saturates to 0
+                        Scalar::from_uint(0u128, Size::from_bits(num_bits))
                     };
                     self.write_scalar(val, dest)?;
                 } else {
diff --git a/src/test/run-pass/const-int-saturating-arith.rs b/src/test/run-pass/const-int-saturating-arith.rs
index 283a2a2484f..92372e073cf 100644
--- a/src/test/run-pass/const-int-saturating-arith.rs
+++ b/src/test/run-pass/const-int-saturating-arith.rs
@@ -5,9 +5,11 @@ const INT_I128: i128 = i128::max_value().saturating_add(1);
 const INT_I128_NEG: i128 = i128::min_value().saturating_add(-1);
 
 const INT_U32_NO_SUB: u32 = (42 as u32).saturating_sub(2);
+const INT_U32_SUB: u32 = (1 as u32).saturating_sub(2);
 const INT_I32_NO_SUB: i32 = (-42 as i32).saturating_sub(2);
 const INT_I32_NEG_SUB: i32 = i32::min_value().saturating_sub(1);
 const INT_I32_POS_SUB: i32 = i32::max_value().saturating_sub(-1);
+const INT_U128_SUB: u128 = (0 as u128).saturating_sub(1);
 const INT_I128_NEG_SUB: i128 = i128::min_value().saturating_sub(1);
 const INT_I128_POS_SUB: i128 = i128::max_value().saturating_sub(-1);
 
@@ -19,9 +21,11 @@ fn main() {
     assert_eq!(INT_I128_NEG, i128::min_value());
 
     assert_eq!(INT_U32_NO_SUB, 40);
+    assert_eq!(INT_U32_SUB, 0);
     assert_eq!(INT_I32_NO_SUB, -44);
     assert_eq!(INT_I32_NEG_SUB, i32::min_value());
     assert_eq!(INT_I32_POS_SUB, i32::max_value());
+    assert_eq!(INT_U128_SUB, 0);
     assert_eq!(INT_I128_NEG_SUB, i128::min_value());
     assert_eq!(INT_I128_POS_SUB, i128::max_value());
 }