diff options
| author | varkor <github@varkor.com> | 2018-05-20 01:54:22 +0100 |
|---|---|---|
| committer | varkor <github@varkor.com> | 2018-08-16 20:09:04 +0100 |
| commit | 121fa8d499b5d0db6d4b6c25458bd87ea38decc2 (patch) | |
| tree | ac375018a474810efc8f2bb75b72ff193d3b3300 /src | |
| parent | b8702a0b1dd66f422d2666de1d50c344c0f008c0 (diff) | |
| download | rust-121fa8d499b5d0db6d4b6c25458bd87ea38decc2.tar.gz rust-121fa8d499b5d0db6d4b6c25458bd87ea38decc2.zip | |
Fix handling of signed integers
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_mir/hair/pattern/_match.rs | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 5941e71cfa2..03b1ea44c75 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -469,20 +469,16 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyInt(int_ty) if exhaustive_integer_patterns => { use syntax::ast::IntTy::*; let (min, max, ty) = match int_ty { - Isize => (isize::MIN as i128, isize::MAX as i128, cx.tcx.types.isize), - I8 => ( i8::MIN as i128, i8::MAX as i128, cx.tcx.types.i8), - I16 => ( i16::MIN as i128, i16::MAX as i128, cx.tcx.types.i16), - I32 => ( i32::MIN as i128, i32::MAX as i128, cx.tcx.types.i32), - I64 => ( i64::MIN as i128, i64::MAX as i128, cx.tcx.types.i64), - I128 => ( i128::MIN as i128, i128::MAX as i128, cx.tcx.types.i128), + Isize => (isize::MIN as usize as u128, isize::MAX as usize as u128, cx.tcx.types.isize), + I8 => ( i8::MIN as u8 as u128, i8::MAX as u8 as u128, cx.tcx.types.i8), + I16 => ( i16::MIN as u16 as u128, i16::MAX as u16 as u128, cx.tcx.types.i16), + I32 => ( i32::MIN as u32 as u128, i32::MAX as u32 as u128, cx.tcx.types.i32), + I64 => ( i64::MIN as u64 as u128, i64::MAX as u64 as u128, cx.tcx.types.i64), + I128 => ( i128::MIN as u128 as u128, i128::MAX as u128 as u128, cx.tcx.types.i128), }; value_constructors = true; - vec![ConstantRange(ty::Const::from_bits(cx.tcx, unsafe { - transmute::<i128, u128>(min) - }, ty), - ty::Const::from_bits(cx.tcx, unsafe { - transmute::<i128, u128>(max) - }, ty), + vec![ConstantRange(ty::Const::from_bits(cx.tcx, min, ty), + ty::Const::from_bits(cx.tcx, max, ty), RangeEnd::Included)] } ty::TyUint(uint_ty) if exhaustive_integer_patterns => { @@ -628,6 +624,9 @@ impl<'tcx> Interval<'tcx> { let ty = lo.ty; if let Some(lo) = lo.assert_bits(ty) { if let Some(hi) = hi.assert_bits(ty) { + // Perform a shift if the underlying types are signed, + // which makes the interval arithmetic simpler. + let (lo, hi) = Interval::offset_sign(ty, (lo, hi), true); // Make sure the interval is well-formed. return if lo > hi || lo == hi && *end == RangeEnd::Excluded { None @@ -649,6 +648,38 @@ impl<'tcx> Interval<'tcx> { } } + fn offset_sign(ty: Ty<'tcx>, (lo, hi): (u128, u128), forwards: bool) -> (u128, u128) { + use syntax::ast::IntTy::*; + match ty.sty { + ty::TyInt(int_ty) => { + macro_rules! offset_sign_for_ty { + ($ity:ty, $uty:ty, $min:expr) => {{ + let min = Wrapping($min as $uty); + if forwards { + ((Wrapping(lo as $uty) + min).0 as u128, + (Wrapping(hi as $uty) + min).0 as u128) + } else { + ((Wrapping(lo as $uty) + min).0 as $ity as u128, + (Wrapping(hi as $uty) + min).0 as $ity as u128) + } + }} + } + match int_ty { + Isize => offset_sign_for_ty!(isize, usize, isize::MIN), + I8 => offset_sign_for_ty!(i8, u8, i8::MIN), + I16 => offset_sign_for_ty!(i16, u16, i16::MIN), + I32 => offset_sign_for_ty!(i32, u32, i32::MIN), + I64 => offset_sign_for_ty!(i64, u64, i64::MIN), + I128 => offset_sign_for_ty!(i128, u128, i128::MIN), + } + } + ty::TyUint(_) | ty::TyChar => { + (lo, hi) + } + _ => bug!("`Interval` should only contain integer types") + } + } + fn into_inner(self) -> (u128, u128) { (self.lo, self.hi) } @@ -692,6 +723,7 @@ fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // Convert the remaining ranges from pairs to inclusive `ConstantRange`s. let ty = pat_interval.ty; remaining_ranges.into_iter().map(|(lo, hi)| { + let (lo, hi) = Interval::offset_sign(ty, (lo, hi), false); ConstantRange(ty::Const::from_bits(cx.tcx, lo, ty), ty::Const::from_bits(cx.tcx, hi, ty), RangeEnd::Included) |
