Skip to content

Commit 00f9ff2

Browse files
committed
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 #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.
2 parents e6c54a1 + c0248c0 commit 00f9ff2

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

src/libcore/num/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -586,14 +586,14 @@ macro_rules! int_impl {
586586
fn rotate_left(self, n: uint) -> $T {
587587
// Protect against undefined behaviour for over-long bit shifts
588588
let n = n % $BITS;
589-
(self << n) | (self >> ($BITS - n))
589+
(self << n) | (self >> (($BITS - n) % $BITS))
590590
}
591591

592592
#[inline]
593593
fn rotate_right(self, n: uint) -> $T {
594594
// Protect against undefined behaviour for over-long bit shifts
595595
let n = n % $BITS;
596-
(self >> n) | (self << ($BITS - n))
596+
(self >> n) | (self << (($BITS - n) % $BITS))
597597
}
598598

599599
#[inline]

src/libcoretest/num/int_macros.rs

+9
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ mod tests {
114114
assert_eq!(_1.rotate_left(124), _1);
115115
assert_eq!(_0.rotate_right(124), _0);
116116
assert_eq!(_1.rotate_right(124), _1);
117+
118+
// Rotating by 0 should have no effect
119+
assert_eq!(A.rotate_left(0), A);
120+
assert_eq!(B.rotate_left(0), B);
121+
assert_eq!(C.rotate_left(0), C);
122+
// Rotating by a multiple of word size should also have no effect
123+
assert_eq!(A.rotate_left(64), A);
124+
assert_eq!(B.rotate_left(64), B);
125+
assert_eq!(C.rotate_left(64), C);
117126
}
118127

119128
#[test]

src/libcoretest/num/uint_macros.rs

+9
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ mod tests {
7474
assert_eq!(_1.rotate_left(124), _1);
7575
assert_eq!(_0.rotate_right(124), _0);
7676
assert_eq!(_1.rotate_right(124), _1);
77+
78+
// Rotating by 0 should have no effect
79+
assert_eq!(A.rotate_left(0), A);
80+
assert_eq!(B.rotate_left(0), B);
81+
assert_eq!(C.rotate_left(0), C);
82+
// Rotating by a multiple of word size should also have no effect
83+
assert_eq!(A.rotate_left(64), A);
84+
assert_eq!(B.rotate_left(64), B);
85+
assert_eq!(C.rotate_left(64), C);
7786
}
7887

7988
#[test]

0 commit comments

Comments
 (0)