Skip to content

Commit f857199

Browse files
committed
fix saturating_sub() underflow for unsigned ints #58030
1 parent c5586eb commit f857199

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

src/librustc_mir/interpret/intrinsics.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
139139
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
140140
}
141141
} else {
142-
if num_bits == 128 {
143-
Scalar::from_uint(u128::max_value(), Size::from_bits(128))
144-
} else {
145-
Scalar::from_uint(u128::max_value() & ((1 << num_bits) - 1),
146-
Size::from_bits(num_bits))
147-
}
142+
Scalar::from_uint(u128::max_value() >> (128 - num_bits), Size::from_bits(num_bits))
148143
};
149144
self.write_scalar(val, dest)?;
150145
} else {
@@ -158,12 +153,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
158153
if overflowed {
159154
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
160155
let num_bits = l.layout.size.bits();
161-
let val = if first_term & (1 << (num_bits-1)) == 0 { // first term is positive
162-
// so overflow is positive
163-
Scalar::from_uint((1u128 << (num_bits - 1)) - 1, Size::from_bits(num_bits))
156+
let val = if l.layout.abi.is_signed() {
157+
if first_term & (1 << (num_bits-1)) == 0 { // first term is positive
158+
// so overflow is positive
159+
Scalar::from_uint((1u128 << (num_bits - 1)) - 1, Size::from_bits(num_bits))
160+
} else {
161+
// if first term negative, overflow must be negative
162+
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
163+
}
164164
} else {
165-
// if first term negative, overflow must be negative
166-
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
165+
// unsigned underflow saturates to 0
166+
Scalar::from_uint(0u128, Size::from_bits(num_bits))
167167
};
168168
self.write_scalar(val, dest)?;
169169
} else {

src/test/run-pass/const-int-saturating-arith.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ const INT_I128: i128 = i128::max_value().saturating_add(1);
55
const INT_I128_NEG: i128 = i128::min_value().saturating_add(-1);
66

77
const INT_U32_NO_SUB: u32 = (42 as u32).saturating_sub(2);
8+
const INT_U32_SUB: u32 = (1 as u32).saturating_sub(2);
89
const INT_I32_NO_SUB: i32 = (-42 as i32).saturating_sub(2);
910
const INT_I32_NEG_SUB: i32 = i32::min_value().saturating_sub(1);
1011
const INT_I32_POS_SUB: i32 = i32::max_value().saturating_sub(-1);
12+
const INT_U128_SUB: u128 = (0 as u128).saturating_sub(1);
1113
const INT_I128_NEG_SUB: i128 = i128::min_value().saturating_sub(1);
1214
const INT_I128_POS_SUB: i128 = i128::max_value().saturating_sub(-1);
1315

@@ -19,9 +21,11 @@ fn main() {
1921
assert_eq!(INT_I128_NEG, i128::min_value());
2022

2123
assert_eq!(INT_U32_NO_SUB, 40);
24+
assert_eq!(INT_U32_SUB, 0);
2225
assert_eq!(INT_I32_NO_SUB, -44);
2326
assert_eq!(INT_I32_NEG_SUB, i32::min_value());
2427
assert_eq!(INT_I32_POS_SUB, i32::max_value());
28+
assert_eq!(INT_U128_SUB, 0);
2529
assert_eq!(INT_I128_NEG_SUB, i128::min_value());
2630
assert_eq!(INT_I128_POS_SUB, i128::max_value());
2731
}

0 commit comments

Comments
 (0)