about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-07-03 06:11:38 +0000
committerbors <bors@rust-lang.org>2014-07-03 06:11:38 +0000
commit00f9ff2b41ffd1f1c187533570d979018724852a (patch)
tree3213e9e5f8328493feb5bc417d55f2460f117c8b
parente6c54a12c4d209de9f438b4722657ca381f969a2 (diff)
parentc0248c0839cfdf5b7030f4191ea7aed0981b9e4e (diff)
downloadrust-00f9ff2b41ffd1f1c187533570d979018724852a.tar.gz
rust-00f9ff2b41ffd1f1c187533570d979018724852a.zip
auto merge of #15324 : sneves/rust/master, r=alexcrichton
The current implementation of `rotate_left` and `rotate_right` are incorrect when the rotation amount is 0, or a multiple of the input's bitsize. When `n = 0`, the expression

    (self >> n) | (self << ($BITS - n))

results in a shift left by `$BITS` bits, which is undefined behavior (see https://github.com/rust-lang/rust/issues/10183), and currently results in a hardcoded `-1` value, instead of the original input value. Reducing `($BITS - n)` modulo `$BITS`, simplified to `(-n % $BITS)`, fixes this problem.
-rw-r--r--src/libcore/num/mod.rs4
-rw-r--r--src/libcoretest/num/int_macros.rs9
-rw-r--r--src/libcoretest/num/uint_macros.rs9
3 files changed, 20 insertions, 2 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index b32e4167da1..1fae362471d 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -586,14 +586,14 @@ macro_rules! int_impl {
             fn rotate_left(self, n: uint) -> $T {
                 // Protect against undefined behaviour for over-long bit shifts
                 let n = n % $BITS;
-                (self << n) | (self >> ($BITS - n))
+                (self << n) | (self >> (($BITS - n) % $BITS))
             }
 
             #[inline]
             fn rotate_right(self, n: uint) -> $T {
                 // Protect against undefined behaviour for over-long bit shifts
                 let n = n % $BITS;
-                (self >> n) | (self << ($BITS - n))
+                (self >> n) | (self << (($BITS - n) % $BITS))
             }
 
             #[inline]
diff --git a/src/libcoretest/num/int_macros.rs b/src/libcoretest/num/int_macros.rs
index 940b036ca90..d078b514085 100644
--- a/src/libcoretest/num/int_macros.rs
+++ b/src/libcoretest/num/int_macros.rs
@@ -114,6 +114,15 @@ mod tests {
         assert_eq!(_1.rotate_left(124), _1);
         assert_eq!(_0.rotate_right(124), _0);
         assert_eq!(_1.rotate_right(124), _1);
+
+        // Rotating by 0 should have no effect
+        assert_eq!(A.rotate_left(0), A);
+        assert_eq!(B.rotate_left(0), B);
+        assert_eq!(C.rotate_left(0), C);
+        // Rotating by a multiple of word size should also have no effect
+        assert_eq!(A.rotate_left(64), A);
+        assert_eq!(B.rotate_left(64), B);
+        assert_eq!(C.rotate_left(64), C);
     }
 
     #[test]
diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcoretest/num/uint_macros.rs
index 2272af67daf..aefaa90520e 100644
--- a/src/libcoretest/num/uint_macros.rs
+++ b/src/libcoretest/num/uint_macros.rs
@@ -74,6 +74,15 @@ mod tests {
         assert_eq!(_1.rotate_left(124), _1);
         assert_eq!(_0.rotate_right(124), _0);
         assert_eq!(_1.rotate_right(124), _1);
+
+        // Rotating by 0 should have no effect
+        assert_eq!(A.rotate_left(0), A);
+        assert_eq!(B.rotate_left(0), B);
+        assert_eq!(C.rotate_left(0), C);
+        // Rotating by a multiple of word size should also have no effect
+        assert_eq!(A.rotate_left(64), A);
+        assert_eq!(B.rotate_left(64), B);
+        assert_eq!(C.rotate_left(64), C);
     }
 
     #[test]