about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-05-20 01:54:22 +0100
committervarkor <github@varkor.com>2018-08-16 20:09:04 +0100
commit121fa8d499b5d0db6d4b6c25458bd87ea38decc2 (patch)
treeac375018a474810efc8f2bb75b72ff193d3b3300 /src
parentb8702a0b1dd66f422d2666de1d50c344c0f008c0 (diff)
downloadrust-121fa8d499b5d0db6d4b6c25458bd87ea38decc2.tar.gz
rust-121fa8d499b5d0db6d4b6c25458bd87ea38decc2.zip
Fix handling of signed integers
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs56
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)