Skip to content

Commit 852701a

Browse files
committed
Auto merge of #57978 - varkor:fix-irrefutable-integer-range-match, r=oli-obk
Fix bug in integer range matching Fixes #57894.
2 parents 23d8d0c + cd1047e commit 852701a

File tree

2 files changed

+21
-7
lines changed

2 files changed

+21
-7
lines changed

src/librustc_mir/build/matches/simplify.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -106,27 +106,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
106106
}
107107

108108
PatternKind::Range(PatternRange { lo, hi, ty, end }) => {
109-
let range = match ty.sty {
109+
let (range, bias) = match ty.sty {
110110
ty::Char => {
111-
Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32)))
111+
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
112112
}
113113
ty::Int(ity) => {
114114
// FIXME(49937): refactor these bit manipulations into interpret.
115115
let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
116-
let min = 1u128 << (size.bits() - 1);
117-
let max = (1u128 << (size.bits() - 1)) - 1;
118-
Some((min, max, size))
116+
let max = !0u128 >> (128 - size.bits());
117+
let bias = 1u128 << (size.bits() - 1);
118+
(Some((0, max, size)), bias)
119119
}
120120
ty::Uint(uty) => {
121121
// FIXME(49937): refactor these bit manipulations into interpret.
122122
let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
123123
let max = !0u128 >> (128 - size.bits());
124-
Some((0, max, size))
124+
(Some((0, max, size)), 0)
125125
}
126-
_ => None,
126+
_ => (None, 0),
127127
};
128128
if let Some((min, max, sz)) = range {
129129
if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
130+
// We want to compare ranges numerically, but the order of the bitwise
131+
// representation of signed integers does not match their numeric order.
132+
// Thus, to correct the ordering, we need to shift the range of signed
133+
// integers to correct the comparison. This is achieved by XORing with a
134+
// bias (see pattern/_match.rs for another pertinent example of this
135+
// pattern).
136+
let (lo, hi) = (lo ^ bias, hi ^ bias);
130137
if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
131138
// Irrefutable pattern match.
132139
return Ok(());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// run-pass
2+
3+
fn main() {
4+
assert_eq!(false, match -50_i8 { -128i8..=-101i8 => true, _ => false, });
5+
6+
assert_eq!(false, if let -128i8..=-101i8 = -50_i8 { true } else { false });
7+
}

0 commit comments

Comments
 (0)