Skip to content

Commit 3c0b2d3

Browse files
NCGThompsonCentri3
andcommitted
Updated statically_known and pow
Co-Authored-By: Catherine Flores <[email protected]>
1 parent 49d9676 commit 3c0b2d3

File tree

3 files changed

+42
-33
lines changed

3 files changed

+42
-33
lines changed

library/core/src/intrinsics.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -2525,15 +2525,30 @@ extern "rust-intrinsic" {
25252525
/// or `false`, and the caller has to ensure sound behavior for both cases.
25262526
/// In other words, the following code has *Undefined Behavior*:
25272527
///
2528-
/// ```rust
2529-
/// if !is_val_statically_known(0) { unreachable_unchecked(); }
2528+
/// ```
2529+
/// #![feature(is_val_statically_known)]
2530+
/// #![feature(core_intrinsics)]
2531+
/// # #![allow(internal_features)]
2532+
/// use std::hint::unreachable_unchecked;
2533+
/// use std::intrinsics::is_val_statically_known;
2534+
///
2535+
/// unsafe {
2536+
/// if !is_val_statically_known(0) { unreachable_unchecked(); }
2537+
/// }
25302538
/// ```
25312539
///
25322540
/// This also means that the following code's behavior is unspecified; it
25332541
/// may panic, or it may not:
25342542
///
2535-
/// ```rust,no_run
2536-
/// assert_eq!(is_val_statically_known(0), black_box(is_val_statically_known(0)))
2543+
/// ```no_run
2544+
/// #![feature(is_val_statically_known)]
2545+
/// #![feature(core_intrinsics)]
2546+
/// # #![allow(internal_features)]
2547+
/// use std::intrinsics::is_val_statically_known;
2548+
///
2549+
/// unsafe {
2550+
/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
2551+
/// }
25372552
/// ```
25382553
///
25392554
/// Unsafe code may not rely on `is_val_statically_known` returning any
@@ -2552,7 +2567,7 @@ extern "rust-intrinsic" {
25522567

25532568
// FIXME: Seems using `unstable` here completely ignores `rustc_allow_const_fn_unstable`
25542569
// and thus compiling stage0 core doesn't work.
2555-
#[rustc_const_stable(feature = "is_val_statically_known", since = "never")]
2570+
#[rustc_const_stable(feature = "is_val_statically_known", since = "0.0.0")]
25562571
#[cfg(bootstrap)]
25572572
pub const unsafe fn is_val_statically_known<T>(t: T) -> bool {
25582573
mem::forget(t);

library/core/src/num/int_macros.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -2088,28 +2088,28 @@ macro_rules! int_impl {
20882088
without modifying the original"]
20892089
#[inline]
20902090
#[rustc_inherit_overflow_checks]
2091+
#[track_caller] // Hides the hackish overflow check for powers of two.
20912092
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
20922093
pub const fn pow(self, mut exp: u32) -> Self {
20932094
// SAFETY: This path has the same behavior as the other.
20942095
if unsafe { intrinsics::is_val_statically_known(self) }
20952096
&& self > 0
20962097
&& (self & (self - 1) == 0)
20972098
{
2098-
let power_used = match self.checked_ilog2() {
2099-
Some(v) => v,
2100-
// SAFETY: We just checked this is a power of two. and above zero.
2101-
None => unsafe { core::hint::unreachable_unchecked() },
2099+
// SAFETY: We just checked this is a power of two. and above zero.
2100+
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
2101+
let num_shl = power_used.saturating_mul(exp);
2102+
let res = match (1 as Self).checked_shl(num_shl) {
2103+
Some(x) => x,
2104+
None => 0
21022105
};
2103-
// So it panics. Have to use `overflowing_mul` to efficiently set the
2104-
// result to 0 if not.
2105-
#[cfg(debug_assertions)]
2106-
{
2107-
_ = power_used * exp;
2106+
2107+
#[allow(arithmetic_overflow)]
2108+
if res <= 0 {
2109+
// So it panics.
2110+
_ = Self::MAX * Self::MAX;
21082111
}
2109-
let (num_shl, overflowed) = power_used.overflowing_mul(exp);
2110-
let fine = !overflowed
2111-
& (num_shl < (mem::size_of::<Self>() * 8) as u32);
2112-
(1 << num_shl) * fine as Self
2112+
res
21132113
} else {
21142114
if exp == 0 {
21152115
return 1;

library/core/src/num/uint_macros.rs

+9-15
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,7 @@ macro_rules! uint_impl {
19731973
without modifying the original"]
19741974
#[inline]
19751975
#[rustc_inherit_overflow_checks]
1976+
#[track_caller] // Hides the hackish overflow check for powers of two.
19761977
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
19771978
pub const fn pow(self, mut exp: u32) -> Self {
19781979
// LLVM now knows that `self` is a constant value, but not a
@@ -1990,22 +1991,15 @@ macro_rules! uint_impl {
19901991
if unsafe { intrinsics::is_val_statically_known(self) }
19911992
&& self.is_power_of_two()
19921993
{
1993-
let power_used = match self.checked_ilog2() {
1994-
Some(v) => v,
1995-
// SAFETY: We just checked this is a power of two. `0` is not a
1996-
// power of two.
1997-
None => unsafe { core::hint::unreachable_unchecked() },
1998-
};
1999-
// So it panics. Have to use `overflowing_mul` to efficiently set the
2000-
// result to 0 if not.
2001-
#[cfg(debug_assertions)]
2002-
{
2003-
_ = power_used * exp;
1994+
// SAFETY: We just checked this is a power of two. and above zero.
1995+
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
1996+
let num_shl = power_used.saturating_mul(exp);
1997+
1998+
#[allow(arithmetic_overflow)]
1999+
match (1 as Self).checked_shl(num_shl) {
2000+
Some(x) => x,
2001+
None => Self::MAX * Self::MAX * 0
20042002
}
2005-
let (num_shl, overflowed) = power_used.overflowing_mul(exp);
2006-
let fine = !overflowed
2007-
& (num_shl < (mem::size_of::<Self>() * 8) as u32);
2008-
(1 << num_shl) * fine as Self
20092003
} else {
20102004
if exp == 0 {
20112005
return 1;

0 commit comments

Comments
 (0)