summaryrefslogtreecommitdiffstats
path: root/src/test/ui/numbers-arithmetic/shift-near-oflo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/numbers-arithmetic/shift-near-oflo.rs')
-rw-r--r--src/test/ui/numbers-arithmetic/shift-near-oflo.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/test/ui/numbers-arithmetic/shift-near-oflo.rs b/src/test/ui/numbers-arithmetic/shift-near-oflo.rs
new file mode 100644
index 000000000..55006a113
--- /dev/null
+++ b/src/test/ui/numbers-arithmetic/shift-near-oflo.rs
@@ -0,0 +1,100 @@
+// run-pass
+// compile-flags: -C debug-assertions
+
+// Check that we do *not* overflow on a number of edge cases.
+// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
+
+fn main() {
+ test_left_shift();
+ test_right_shift();
+}
+
+pub static mut HACK: i32 = 0;
+
+// Work around constant-evaluation
+// The point of this test is to exercise the code generated for execution at runtime,
+// `id` can never be flagged as a const fn by future aggressive analyses...
+// due to the modification of the static
+#[inline(never)]
+fn id<T>(x: T) -> T {
+ unsafe { HACK += 1; }
+ x
+}
+
+fn test_left_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
+ let x = (1 as $iN) << id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $uN) << id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $iN) << id($max_rhs);
+ assert_eq!(x, $expect_i);
+ let x = (1 as $uN) << id($max_rhs);
+ assert_eq!(x, $expect_u);
+ // high-order bits on LHS are silently discarded without panic.
+ let x = (3 as $iN) << id($max_rhs);
+ assert_eq!(x, $expect_i);
+ let x = (3 as $uN) << id($max_rhs);
+ assert_eq!(x, $expect_u);
+ } }
+ }
+
+ let x = 1_i8 << id(0);
+ assert_eq!(x, 1);
+ let x = 1_u8 << id(0);
+ assert_eq!(x, 1);
+ let x = 1_i8 << id(7);
+ assert_eq!(x, i8::MIN);
+ let x = 1_u8 << id(7);
+ assert_eq!(x, 0x80);
+ // high-order bits on LHS are silently discarded without panic.
+ let x = 3_i8 << id(7);
+ assert_eq!(x, i8::MIN);
+ let x = 3_u8 << id(7);
+ assert_eq!(x, 0x80);
+
+ // above is (approximately) expanded from:
+ tests!(i8, u8, 7, i8::MIN, 0x80_u8);
+
+ tests!(i16, u16, 15, i16::MIN, 0x8000_u16);
+ tests!(i32, u32, 31, i32::MIN, 0x8000_0000_u32);
+ tests!(i64, u64, 63, i64::MIN, 0x8000_0000_0000_0000_u64);
+}
+
+fn test_right_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($iN:ty, $uN:ty, $max_rhs:expr,
+ $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
+ { {
+ let x = (1 as $iN) >> id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $uN) >> id(0);
+ assert_eq!(x, 1);
+ let x = ($highbit_i) >> id($max_rhs-1);
+ assert_eq!(x, 1);
+ let x = ($highbit_u) >> id($max_rhs);
+ assert_eq!(x, 1);
+ // sign-bit is carried by arithmetic right shift
+ let x = ($signbit_i) >> id($max_rhs);
+ assert_eq!(x, -1);
+ // low-order bits on LHS are silently discarded without panic.
+ let x = ($highbit_i + 1) >> id($max_rhs-1);
+ assert_eq!(x, 1);
+ let x = ($highbit_u + 1) >> id($max_rhs);
+ assert_eq!(x, 1);
+ let x = ($signbit_i + 1) >> id($max_rhs);
+ assert_eq!(x, -1);
+ } }
+ }
+
+ tests!(i8, u8, 7, i8::MIN, 0x40_i8, 0x80_u8);
+ tests!(i16, u16, 15, i16::MIN, 0x4000_u16, 0x8000_u16);
+ tests!(i32, u32, 31, i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
+ tests!(i64, u64, 63, i64::MIN,
+ 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
+}