Change:
I tried this code: I expected that a operation would specifically not cause UB on overflow. Instead, this happened (): It most recently worked on: I didn't bisect this, but I believe it started happening with GH PR . <details<summaryBacktrace</summary<p</p</detailsI believe GH PR is the cause. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
I feel like int macro changes would have best been split out into a separate PR^^
WG-prioritization assigning priority (). label -I-prioritize +P-high +T-compiler
claim
assign It looks like oli-obk already fixed it. release-assignment
Just to make sure it's not lost -- we also need to handle the case where rounds down.
We want to check if is less than or not. Using algebra, we know that in real life as long as 0: ≥ ≡ ≥ / However, we can't use exact division, only floor division (f.d.). Unfortunately, ≥ ≢ ≥ f.d. and ≥ ≢ f.d. Since we are dealing exclusively with non-negative integers, we can say that ≥ ≡ - 1 ≡ ( - 1) / , that = ( - 1) / implies ( - 1) / = ( - 1) f.d. , and that / - ( - 1) f.d. ≤ 1 From there, we can work out that ≥ ≡ ( - 1) f.d. and ( - 1) f.d. can be computed in Rust with Now you don't need to go math golfing.
For signed types, note that is still an overflow, but is its .
Right. Since overflow on is dependent on the sign of the base, we use a separate check for that.
Oh, you mean this? Then OK, but that could use a comment.
The revert landed after the branch move, so let's re-open until that's backported.
Backport was done in .

Discussion:
// // Language features: // tidy-alphabetical-start <del> #![cfg_attr(not(bootstrap), feature(is_val_statically_known))] </del> #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)]

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn checked_pow(self, mut exp: u32) -> Option<Self> { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.unsigned_abs().is_power_of_two() { if self == 1 { // Avoid divide by zero return Some(1); } if self == -1 { // Avoid divide by zero return Some(if exp & 1 != 0 { -1 } else { 1 }); } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; if exp > Self::BITS / power_used { return None; } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used let res = unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )}; // LLVM doesn't always optimize out the checks // at the ir level. let sign = self.is_negative() && exp & 1 != 0; if !sign && res == Self::MIN  { None } else if sign { Some(res.wrapping_neg()) } else { Some(res) } } else { if exp == 0 { return Some(1); } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); } exp /= 2; base = try_opt!(base.checked_mul(base)); </del> <ins> if exp == 0 { return Some(1); } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); </ins> } <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.checked_mul(base) </del> <ins> exp /= 2; base = try_opt!(base.checked_mul(base)); </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.checked_mul(base) </ins> } /// Strict exponentiation. Computes `self.pow(exp)`, panicking if

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.unsigned_abs().is_power_of_two() { if self == 1 { // Avoid divide by zero return 1; } if self == -1 { // Avoid divide by zero return if exp & 1 != 0 { -1 } else { 1 }; } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; if exp > Self::BITS / power_used { return 0; } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used let res = unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )}; // LLVM doesn't always optimize out the checks // at the ir level. let sign = self.is_negative() && exp & 1 != 0; if sign { res.wrapping_neg() } else { res } } else { if exp == 0 { return 1; } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); } exp /= 2; base = base.wrapping_mul(base); } </del> <ins> if exp == 0 { return 1; } let mut base = self; let mut acc: Self = 1; </ins> <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.wrapping_mul(base) </del> <ins> while exp > 1 { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); } exp /= 2; base = base.wrapping_mul(base); </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.wrapping_mul(base) </ins> } /// Calculates `self` + `rhs`

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.unsigned_abs().is_power_of_two() { if self == 1 { // Avoid divide by zero return (1, false); } if self == -1 { // Avoid divide by zero return (if exp & 1 != 0 { -1 } else { 1 }, false); } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used let res = unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )}; // LLVM doesn't always optimize out the checks // at the ir level. let sign = self.is_negative() && exp & 1 != 0; let overflow = res == Self::MIN; if sign { (res.wrapping_neg(), overflow) } else { (res, overflow) } } else { if exp == 0 { return (1,false); } let mut base = self; let mut acc: Self = 1; let mut overflown = false; // Scratch space for storing results of overflowing_mul. let mut r; while exp > 1 { if (exp & 1) == 1 { r = acc.overflowing_mul(base); acc = r.0; overflown |= r.1; } exp /= 2; r = base.overflowing_mul(base); base = r.0; </del> <ins> if exp == 0 { return (1,false); } let mut base = self; let mut acc: Self = 1; let mut overflown = false; // Scratch space for storing results of overflowing_mul. let mut r; while exp > 1 { if (exp & 1) == 1 { r = acc.overflowing_mul(base); acc = r.0; </ins> overflown |= r.1; } <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. r = acc.overflowing_mul(base); r.1 |= overflown; r </del> <ins> exp /= 2; r = base.overflowing_mul(base); base = r.0; overflown |= r.1; </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. r = acc.overflowing_mul(base); r.1 |= overflown; r </ins> } /// Raises self to the power of `exp`, using exponentiation by squaring.

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] #[rustc_inherit_overflow_checks] <del> #[track_caller] // Hides the hackish overflow check for powers of two. </del> pub const fn pow(self, mut exp: u32) -> Self { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.unsigned_abs().is_power_of_two() { if self == 1 { // Avoid divide by zero return 1; } if self == -1 { // Avoid divide by zero return if exp & 1 != 0 { -1 } else { 1 }; } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; if exp > Self::BITS / power_used { // Division of constants is free #[allow(arithmetic_overflow)] return Self::MAX * Self::MAX * 0; } </del> <ins> if exp == 0 { return 1; } let mut base = self; let mut acc = 1; </ins> <del> // SAFETY: exp <= Self::BITS / power_used let res = unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )}; // LLVM doesn't always optimize out the checks // at the ir level. let sign = self.is_negative() && exp & 1 != 0; #[allow(arithmetic_overflow)] if !sign && res == Self::MIN  { // So it panics. _ = Self::MAX * Self::MAX; } if sign { res.wrapping_neg() } else { res } } else { if exp == 0 { return 1; } let mut base = self; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp /= 2; base = base * base; </del> <ins> while exp > 1 { if (exp & 1) == 1 { acc = acc * base; </ins> } <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc * base </del> <ins> exp /= 2; base = base * base; </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc * base </ins> } /// Returns the square root of the number, rounded down.

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn checked_pow(self, mut exp: u32) -> Option<Self> { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.is_power_of_two() { if self == 1 { // Avoid divide by zero return Some(1); } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; if exp > Self::BITS / power_used { return None; } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used unsafe { Some(intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )) } // LLVM doesn't always optimize out the checks // at the ir level. } else { if exp == 0 { return Some(1); } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); } exp /= 2; base = try_opt!(base.checked_mul(base)); </del> <ins> if exp == 0 { return Some(1); } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); </ins> } <ins> exp /= 2; base = try_opt!(base.checked_mul(base)); } </ins> <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. </del> <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. </ins> <del> acc.checked_mul(base) } </del> <ins> acc.checked_mul(base) </ins> } /// Strict exponentiation. Computes `self.pow(exp)`, panicking if

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.is_power_of_two() { if self == 1 { // Avoid divide by zero return 1; } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; if exp > Self::BITS / power_used {  return 0; } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )} // LLVM doesn't always optimize out the checks // at the ir level. } else { if exp == 0 { return 1; } let mut base = self; let mut acc: Self = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); } exp /= 2; base = base.wrapping_mul(base); } </del> <ins> if exp == 0 { return 1; } let mut base = self; let mut acc: Self = 1; </ins> <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.wrapping_mul(base) </del> <ins> while exp > 1 { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); } exp /= 2; base = base.wrapping_mul(base); </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc.wrapping_mul(base) </ins> } /// Calculates `self` + `rhs`

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { <del> // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.is_power_of_two() { if self == 1 { // Avoid divide by zero return (1, false); } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; if exp > Self::BITS / power_used {  return (0, true); } // Division of constants is free // SAFETY: exp <= Self::BITS / power_used unsafe { (intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self ), false) } // LLVM doesn't always optimize out the checks // at the ir level. } else { if exp == 0{ return (1,false); } let mut base = self; let mut acc: Self = 1; let mut overflown = false; // Scratch space for storing results of overflowing_mul. let mut r; while exp > 1 { if (exp & 1) == 1 { r = acc.overflowing_mul(base); acc = r.0; overflown |= r.1; } exp /= 2; r = base.overflowing_mul(base); base = r.0; </del> <ins> if exp == 0{ return (1,false); } let mut base = self; let mut acc: Self = 1; let mut overflown = false; // Scratch space for storing results of overflowing_mul. let mut r; while exp > 1 { if (exp & 1) == 1 { r = acc.overflowing_mul(base); acc = r.0; </ins> overflown |= r.1; } <ins> exp /= 2; r = base.overflowing_mul(base); base = r.0; overflown |= r.1; } </ins> <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. r = acc.overflowing_mul(base); r.1 |= overflown; </del> <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. r = acc.overflowing_mul(base); r.1 |= overflown; </ins> <del> r } </del> <ins> r </ins> } /// Raises self to the power of `exp`, using exponentiation by squaring.

#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation,  without modifying the original"] <del> #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] </del> #[inline] #[rustc_inherit_overflow_checks] <del> #[track_caller] // Hides the hackish overflow check for powers of two. </del> pub const fn pow(self, mut exp: u32) -> Self { <del> // LLVM now knows that `self` is a constant value, but not a // constant in Rust. This allows us to compute the power used at // compile-time. // // This will likely add a branch in debug builds, but this should // be ok. // // This is a massive performance boost in release builds as you can // get the power of a power of two and the exponent through a `shl` // instruction, but we must add a couple more checks for parity with // our own `pow`. // SAFETY: This path has the same behavior as the other. if unsafe { intrinsics::is_val_statically_known(self) } && self.is_power_of_two() { if self == 1 { // Avoid divide by zero return 1; } // SAFETY: We just checked this is a power of two. and above zero. let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; if exp > Self::BITS / power_used { // Division of constants is free #[allow(arithmetic_overflow)] return Self::MAX * Self::MAX * 0; } </del> <ins> if exp == 0 { return 1; } let mut base = self; let mut acc = 1; </ins> <del> // SAFETY: exp <= Self::BITS / power_used unsafe { intrinsics::unchecked_shl( 1 as Self, intrinsics::unchecked_mul(power_used, exp) as Self )} // LLVM doesn't always optimize out the checks // at the ir level. } else { if exp == 0 { return 1; } let mut base = self; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp /= 2; base = base * base; </del> <ins> while exp > 1 { if (exp & 1) == 1 { acc = acc * base; </ins> } <del> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc * base </del> <ins> exp /= 2; base = base * base; </ins> } <ins> // since exp!=0, finally the exp must be 1. // Deal with the final bit of the exponent separately, since // squaring the base afterwards is not necessary and may cause a // needless overflow. acc * base </ins> } /// Returns the square root of the number, rounded down.

<del> // compile-flags: --crate-type=lib -Zmerge-functions=disabled -O -C overflow-checks=false // CHECK-LABEL: @a( #[no_mangle] pub fn a(exp: u32) -> u64 { // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64 // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64 // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}} // CHECK: ret i64 %{{[^ ]+}} 2u64.pow(exp) } // CHECK-LABEL: @b( #[no_mangle] pub fn b(exp: u32) -> i64 { // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64 // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64 // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}} // CHECK: ret i64 %{{[^ ]+}} 2i64.pow(exp) } // CHECK-LABEL: @c( #[no_mangle] pub fn c(exp: u32) -> u32 { // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 16 // CHECK: %{{[^ ]+}} = shl nuw nsw i32 %exp, 1 // CHECK: %{{[^ ]+}} = shl nuw i32 1, %{{[^ ]+}} // CHECK: %{{[^ ]+}} = select i1 %{{[^ ]+}}, i32 0, i32 %{{[^ ]+}} // CHECK: ret i32 %{{[^ ]+}} 4u32.pow(exp) } // CHECK-LABEL: @d( #[no_mangle] pub fn d(exp: u32) -> u32 { // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6 // CHECK: %{{[^ ]+}} = mul nuw nsw i32 %exp, 5 // CHECK: %{{[^ ]+}} = shl nuw nsw i32 1, %{{[^ ]+}} // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}} // CHECK: ret i32 %{{[^ ]+}} 32u32.pow(exp) } // CHECK-LABEL: @e( #[no_mangle] pub fn e(exp: u32) -> i32 { // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6 // CHECK: %{{[^ ]+}} = mul nuw {{(nsw )?}}i32 %exp, 5 // CHECK: %{{[^ ]+}} = shl nuw {{(nsw )?}}i32 1, %{{[^ ]+}} // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}} // CHECK: ret i32 %{{[^ ]+}} 32i32.pow(exp) } // note: d and e are expected to yield the same IR </del>