about summary refs log tree commit diff
path: root/src/libcore/num
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-03-31 18:06:35 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-03-31 18:06:35 -0700
commit4f643d79fc9573489c178eb283a7da1a1e8402c1 (patch)
tree76b2c1726ef8165e0ef5c1cd5d769c4a11de79ee /src/libcore/num
parent72f59732d7974767650abfc58f8287212e5a1fba (diff)
parent2a9de1d989d7f95846b711eec2695cbd86794ee3 (diff)
downloadrust-4f643d79fc9573489c178eb283a7da1a1e8402c1.tar.gz
rust-4f643d79fc9573489c178eb283a7da1a1e8402c1.zip
rollup merge of #23863: pnkfelix/arith-oflo-const-eval
const_eval : add overflow-checking for {`+`, `-`, `*`, `/`, `<<`, `>>`}.

One tricky detail here: There is some duplication of labor between `rustc::middle::const_eval` and `rustc_trans::trans::consts`. It might be good to explore ways to try to factor out the common structure to the two passes (by abstracting over the particular value-representation used in the compile-time interpreter).

----

Update: Rebased atop #23841

Fix #22531

Fix #23030

Fix #23221

Fix #23235
Diffstat (limited to 'src/libcore/num')
-rw-r--r--src/libcore/num/wrapping.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index bda05a3d9e8..a78eed8ae5f 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -30,6 +30,8 @@ use intrinsics::{i16_mul_with_overflow, u16_mul_with_overflow};
 use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
 use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
 
+use ::{i8,i16,i32,i64,u8,u16,u32,u64};
+
 #[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
 #[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
 pub trait WrappingOps {
@@ -43,6 +45,12 @@ pub trait OverflowingOps {
     fn overflowing_add(self, rhs: Self) -> (Self, bool);
     fn overflowing_sub(self, rhs: Self) -> (Self, bool);
     fn overflowing_mul(self, rhs: Self) -> (Self, bool);
+
+    fn overflowing_div(self, rhs: Self) -> (Self, bool);
+    fn overflowing_rem(self, rhs: Self) -> (Self, bool);
+
+    fn overflowing_shl(self, rhs: u32) -> (Self, bool);
+    fn overflowing_shr(self, rhs: u32) -> (Self, bool);
 }
 
 macro_rules! sh_impl {
@@ -184,6 +192,20 @@ macro_rules! wrapping_impl {
 
 wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
 
+mod shift_max {
+    #![allow(non_upper_case_globals)]
+
+    pub const  i8: u32 = (1 << 3) - 1;
+    pub const i16: u32 = (1 << 4) - 1;
+    pub const i32: u32 = (1 << 5) - 1;
+    pub const i64: u32 = (1 << 6) - 1;
+
+    pub const  u8: u32 = i8;
+    pub const u16: u32 = i16;
+    pub const u32: u32 = i32;
+    pub const u64: u32 = i64;
+}
+
 macro_rules! overflowing_impl {
     ($($t:ident)*) => ($(
         impl OverflowingOps for $t {
@@ -205,6 +227,34 @@ macro_rules! overflowing_impl {
                     concat_idents!($t, _mul_with_overflow)(self, rhs)
                 }
             }
+
+            #[inline(always)]
+            fn overflowing_div(self, rhs: $t) -> ($t, bool) {
+                if self == $t::MIN && rhs == -1 {
+                    (1, true)
+                } else {
+                    (self/rhs, false)
+                }
+            }
+            #[inline(always)]
+            fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
+                if self == $t::MIN && rhs == -1 {
+                    (0, true)
+                } else {
+                    (self % rhs, false)
+                }
+            }
+
+            #[inline(always)]
+            fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
+                (self << (rhs & self::shift_max::$t),
+                 (rhs > self::shift_max::$t))
+            }
+            #[inline(always)]
+            fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
+                (self >> (rhs & self::shift_max::$t),
+                 (rhs > self::shift_max::$t))
+            }
         }
     )*)
 }
@@ -234,6 +284,26 @@ impl OverflowingOps for usize {
             (res.0 as usize, res.1)
         }
     }
+    #[inline(always)]
+    fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+        let (r, f) = (self as u64).overflowing_div(rhs as u64);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+        let (r, f) = (self as u64).overflowing_rem(rhs as u64);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+        let (r, f) = (self as u64).overflowing_shl(rhs);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+        let (r, f) = (self as u64).overflowing_shr(rhs);
+        (r as usize, f)
+    }
 }
 
 #[cfg(target_pointer_width = "32")]
@@ -259,6 +329,26 @@ impl OverflowingOps for usize {
             (res.0 as usize, res.1)
         }
     }
+    #[inline(always)]
+    fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+        let (r, f) = (self as u32).overflowing_div(rhs as u32);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+        let (r, f) = (self as u32).overflowing_rem(rhs as u32);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+        let (r, f) = (self as u32).overflowing_shl(rhs);
+        (r as usize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+        let (r, f) = (self as u32).overflowing_shr(rhs);
+        (r as usize, f)
+    }
 }
 
 #[cfg(target_pointer_width = "64")]
@@ -284,6 +374,26 @@ impl OverflowingOps for isize {
             (res.0 as isize, res.1)
         }
     }
+    #[inline(always)]
+    fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+        let (r, f) = (self as i64).overflowing_div(rhs as i64);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+        let (r, f) = (self as i64).overflowing_rem(rhs as i64);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+        let (r, f) = (self as i64).overflowing_shl(rhs);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+        let (r, f) = (self as i64).overflowing_shr(rhs);
+        (r as isize, f)
+    }
 }
 
 #[cfg(target_pointer_width = "32")]
@@ -309,4 +419,24 @@ impl OverflowingOps for isize {
             (res.0 as isize, res.1)
         }
     }
+    #[inline(always)]
+    fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+        let (r, f) = (self as i32).overflowing_div(rhs as i32);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+        let (r, f) = (self as i32).overflowing_rem(rhs as i32);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+        let (r, f) = (self as i32).overflowing_shl(rhs);
+        (r as isize, f)
+    }
+    #[inline(always)]
+    fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+        let (r, f) = (self as i32).overflowing_shr(rhs);
+        (r as isize, f)
+    }
 }