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.
This commit is contained in:
commit
00f9ff2b41
3 changed files with 20 additions and 2 deletions
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue