From f857199073753956db92e6710f9178e34de4122e Mon Sep 17 00:00:00 2001 From: Patrick McCarter Date: Wed, 6 Feb 2019 18:10:08 -0500 Subject: [PATCH] fix saturating_sub() underflow for unsigned ints #58030 --- src/librustc_mir/interpret/intrinsics.rs | 22 +++++++++---------- .../run-pass/const-int-saturating-arith.rs | 4 ++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 62a0b3d9524a..827c4e62ecda 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 283a2a2484fe..92372e073cf2 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()); }