Skip to content

Commit e6b0590

Browse files
committed
Do sign extension for signed int shift left saturation
1 parent a712539 commit e6b0590

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

library/core/src/num/int_macros.rs

+21-6
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ macro_rules! int_impl {
989989
intrinsics::saturating_sub(0, self)
990990
}
991991

992-
/// Panic-free bitwise shift-left; yields `0` where the shift exceeds the bitwidth of the type.
992+
/// Panic-free bitwise shift-left; saturates to `MIN` or `MAX` instead of wrapping around.
993993
///
994994
/// Note that this is *not* the same as a rotate-left; the RHS of a saturating shift-left is restricted to
995995
/// the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
@@ -1002,19 +1002,34 @@ macro_rules! int_impl {
10021002
///
10031003
/// ```
10041004
/// #![feature(saturating_bit_shifts)]
1005-
#[doc = concat!("assert_eq!(0b0000_0001_u8.saturating_shl(u8::BITS - 1), 0b1000_0000_u8);")]
1006-
#[doc = concat!("assert_eq!(0b0000_0001_u8.saturating_shl(u8::BITS), 0b0000_0000_u8);")]
1005+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS - 2), 1_", stringify!($SelfT), " << ", stringify!($SelfT), "::BITS - 2);")]
1006+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS - 1), ", stringify!($SelfT), "::MAX);")]
1007+
#[doc = concat!("assert_eq!(-1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS - 2), -1_", stringify!($SelfT), " << ", stringify!($SelfT), "::BITS - 2);")]
1008+
#[doc = concat!("assert_eq!(-1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS - 1), ", stringify!($SelfT), "::MIN);")]
1009+
#[doc = concat!("assert_eq!(-1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS), ", stringify!($SelfT), "::MIN);")]
10071010
/// ```
10081011
#[unstable(feature = "saturating_bit_shifts", issue = "103440")]
10091012
#[rustc_const_unstable(feature = "saturating_bit_shifts", issue = "103440")]
10101013
#[must_use = "this returns the result of the operation, \
10111014
without modifying the original"]
10121015
#[inline(always)]
10131016
pub const fn saturating_shl(self, rhs: u32) -> Self {
1014-
if rhs >= <$SelfT>::BITS {
1015-
0
1017+
if rhs == 0 {
1018+
self
10161019
} else {
1017-
self << rhs
1020+
// leading zeros ignoring first bit (which indicates negative values)
1021+
let leading_zeros = (self << 1).leading_zeros();
1022+
let leading_ones = (self << 1).leading_ones();
1023+
1024+
// would overflow => MIN / MAX depending on whether the value is negative or not
1025+
if self >= 0 && leading_zeros < rhs {
1026+
<$SelfT>::MAX
1027+
} else if self < 0 && leading_ones < rhs {
1028+
<$SelfT>::MIN
1029+
} else {
1030+
// normal shift left
1031+
self << rhs
1032+
}
10181033
}
10191034
}
10201035

library/core/src/num/uint_macros.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ macro_rules! uint_impl {
11641164
}
11651165
}
11661166

1167-
/// Panic-free bitwise shift-left; yields `0` where the shift exceeds the bitwidth of the type.
1167+
/// Panic-free bitwise shift-left; saturates `MAX` instead of wrapping around.
11681168
///
11691169
/// Note that this is *not* the same as a rotate-left; the RHS of a saturating shift-left is restricted to
11701170
/// the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
@@ -1177,17 +1177,17 @@ macro_rules! uint_impl {
11771177
///
11781178
/// ```
11791179
/// #![feature(saturating_bit_shifts)]
1180-
#[doc = concat!("assert_eq!(0b0000_0001_u8.saturating_shl(u8::BITS - 1), 0b1000_0000_u8);")]
1181-
#[doc = concat!("assert_eq!(0b0000_0001_u8.saturating_shl(u8::BITS), 0b0000_0000_u8);")]
1180+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS - 1), 1_", stringify!($SelfT), " << ", stringify!($SelfT), "::BITS - 1);")]
1181+
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".saturating_shl(", stringify!($SelfT), "::BITS), ", stringify!($SelfT), "::MAX);")]
11821182
/// ```
11831183
#[unstable(feature = "saturating_bit_shifts", issue = "103440")]
11841184
#[rustc_const_unstable(feature = "saturating_bit_shifts", issue = "103440")]
11851185
#[must_use = "this returns the result of the operation, \
11861186
without modifying the original"]
11871187
#[inline(always)]
11881188
pub const fn saturating_shl(self, rhs: u32) -> Self {
1189-
if rhs >= <$SelfT>::BITS {
1190-
0
1189+
if rhs > self.leading_zeros() {
1190+
<$SelfT>::MAX
11911191
} else {
11921192
self << rhs
11931193
}

0 commit comments

Comments
 (0)