Skip to content

Commit d96951f

Browse files
authored
Rollup merge of #68978 - ecstatic-morse:const-int-pow, r=oli-obk
Make integer exponentiation methods unstably const cc #53718 This makes the following inherent methods on integer primitives into unstable `const fn`: - `pow` - `checked_pow` - `wrapping_pow` - `overflowing_pow` - `saturating_pow` - `next_power_of_two` - `checked_next_power_of_two` - `wrapping_next_power_of_two` Only two changes were made to the implementation of these methods. First, I had to switch from the `?` operator, which is not yet implemented in a const context, to a `try_opt` macro. Second, `next_power_of_two` was using `ops::Add::add` (see the first commit) to "get overflow checks", so I switched to `#[rustc_inherit_overflow_checks]`. I'm not quite sure why the attribute wasn't used in the first place.
2 parents 588f008 + 7fe5eaf commit d96951f

File tree

3 files changed

+86
-23
lines changed

3 files changed

+86
-23
lines changed

src/libcore/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,14 @@
7373
#![feature(const_ascii_ctype_on_intrinsics)]
7474
#![feature(const_alloc_layout)]
7575
#![feature(const_if_match)]
76+
#![feature(const_loop)]
7677
#![feature(const_checked_int_methods)]
7778
#![feature(const_euclidean_int_methods)]
7879
#![feature(const_overflowing_int_methods)]
7980
#![feature(const_saturating_int_methods)]
8081
#![feature(const_int_unchecked_arith)]
82+
#![feature(const_int_pow)]
83+
#![feature(constctlz)]
8184
#![feature(const_panic)]
8285
#![feature(const_fn_union)]
8386
#![feature(const_generics)]

src/libcore/num/mod.rs

+46-23
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ use crate::convert::Infallible;
88
use crate::fmt;
99
use crate::intrinsics;
1010
use crate::mem;
11-
use crate::ops;
1211
use crate::str::FromStr;
1312

13+
// Used because the `?` operator is not allowed in a const context.
14+
macro_rules! try_opt {
15+
($e:expr) => {
16+
match $e {
17+
Some(x) => x,
18+
None => return None,
19+
}
20+
};
21+
}
22+
1423
macro_rules! impl_nonzero_fmt {
1524
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
1625
$(
@@ -993,26 +1002,27 @@ $EndFeature, "
9931002
```"),
9941003

9951004
#[stable(feature = "no_panic_pow", since = "1.34.0")]
1005+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
9961006
#[must_use = "this returns the result of the operation, \
9971007
without modifying the original"]
9981008
#[inline]
999-
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
1009+
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
10001010
let mut base = self;
10011011
let mut acc: Self = 1;
10021012

10031013
while exp > 1 {
10041014
if (exp & 1) == 1 {
1005-
acc = acc.checked_mul(base)?;
1015+
acc = try_opt!(acc.checked_mul(base));
10061016
}
10071017
exp /= 2;
1008-
base = base.checked_mul(base)?;
1018+
base = try_opt!(base.checked_mul(base));
10091019
}
10101020

10111021
// Deal with the final bit of the exponent separately, since
10121022
// squaring the base afterwards is not necessary and may cause a
10131023
// needless overflow.
10141024
if exp == 1 {
1015-
acc = acc.checked_mul(base)?;
1025+
acc = try_opt!(acc.checked_mul(base));
10161026
}
10171027

10181028
Some(acc)
@@ -1180,10 +1190,11 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT
11801190
$EndFeature, "
11811191
```"),
11821192
#[stable(feature = "no_panic_pow", since = "1.34.0")]
1193+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
11831194
#[must_use = "this returns the result of the operation, \
11841195
without modifying the original"]
11851196
#[inline]
1186-
pub fn saturating_pow(self, exp: u32) -> Self {
1197+
pub const fn saturating_pow(self, exp: u32) -> Self {
11871198
match self.checked_pow(exp) {
11881199
Some(x) => x,
11891200
None if self < 0 && exp % 2 == 1 => Self::min_value(),
@@ -1523,10 +1534,11 @@ assert_eq!(3i8.wrapping_pow(6), -39);",
15231534
$EndFeature, "
15241535
```"),
15251536
#[stable(feature = "no_panic_pow", since = "1.34.0")]
1537+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
15261538
#[must_use = "this returns the result of the operation, \
15271539
without modifying the original"]
15281540
#[inline]
1529-
pub fn wrapping_pow(self, mut exp: u32) -> Self {
1541+
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
15301542
let mut base = self;
15311543
let mut acc: Self = 1;
15321544

@@ -1900,10 +1912,11 @@ assert_eq!(3i8.overflowing_pow(5), (-13, true));",
19001912
$EndFeature, "
19011913
```"),
19021914
#[stable(feature = "no_panic_pow", since = "1.34.0")]
1915+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
19031916
#[must_use = "this returns the result of the operation, \
19041917
without modifying the original"]
19051918
#[inline]
1906-
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
1919+
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
19071920
let mut base = self;
19081921
let mut acc: Self = 1;
19091922
let mut overflown = false;
@@ -1949,11 +1962,12 @@ assert_eq!(x.pow(5), 32);",
19491962
$EndFeature, "
19501963
```"),
19511964
#[stable(feature = "rust1", since = "1.0.0")]
1965+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
19521966
#[must_use = "this returns the result of the operation, \
19531967
without modifying the original"]
19541968
#[inline]
19551969
#[rustc_inherit_overflow_checks]
1956-
pub fn pow(self, mut exp: u32) -> Self {
1970+
pub const fn pow(self, mut exp: u32) -> Self {
19571971
let mut base = self;
19581972
let mut acc = 1;
19591973

@@ -3119,26 +3133,27 @@ Basic usage:
31193133
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, "
31203134
```"),
31213135
#[stable(feature = "no_panic_pow", since = "1.34.0")]
3136+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
31223137
#[must_use = "this returns the result of the operation, \
31233138
without modifying the original"]
31243139
#[inline]
3125-
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
3140+
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
31263141
let mut base = self;
31273142
let mut acc: Self = 1;
31283143

31293144
while exp > 1 {
31303145
if (exp & 1) == 1 {
3131-
acc = acc.checked_mul(base)?;
3146+
acc = try_opt!(acc.checked_mul(base));
31323147
}
31333148
exp /= 2;
3134-
base = base.checked_mul(base)?;
3149+
base = try_opt!(base.checked_mul(base));
31353150
}
31363151

31373152
// Deal with the final bit of the exponent separately, since
31383153
// squaring the base afterwards is not necessary and may cause a
31393154
// needless overflow.
31403155
if exp == 1 {
3141-
acc = acc.checked_mul(base)?;
3156+
acc = try_opt!(acc.checked_mul(base));
31423157
}
31433158

31443159
Some(acc)
@@ -3234,10 +3249,11 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT
32343249
$EndFeature, "
32353250
```"),
32363251
#[stable(feature = "no_panic_pow", since = "1.34.0")]
3252+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
32373253
#[must_use = "this returns the result of the operation, \
32383254
without modifying the original"]
32393255
#[inline]
3240-
pub fn saturating_pow(self, exp: u32) -> Self {
3256+
pub const fn saturating_pow(self, exp: u32) -> Self {
32413257
match self.checked_pow(exp) {
32423258
Some(x) => x,
32433259
None => Self::max_value(),
@@ -3527,10 +3543,11 @@ Basic usage:
35273543
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
35283544
```"),
35293545
#[stable(feature = "no_panic_pow", since = "1.34.0")]
3546+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
35303547
#[must_use = "this returns the result of the operation, \
35313548
without modifying the original"]
35323549
#[inline]
3533-
pub fn wrapping_pow(self, mut exp: u32) -> Self {
3550+
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
35343551
let mut base = self;
35353552
let mut acc: Self = 1;
35363553

@@ -3853,10 +3870,11 @@ Basic usage:
38533870
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
38543871
```"),
38553872
#[stable(feature = "no_panic_pow", since = "1.34.0")]
3873+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
38563874
#[must_use = "this returns the result of the operation, \
38573875
without modifying the original"]
38583876
#[inline]
3859-
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
3877+
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
38603878
let mut base = self;
38613879
let mut acc: Self = 1;
38623880
let mut overflown = false;
@@ -3899,11 +3917,12 @@ Basic usage:
38993917
", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
39003918
```"),
39013919
#[stable(feature = "rust1", since = "1.0.0")]
3920+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
39023921
#[must_use = "this returns the result of the operation, \
39033922
without modifying the original"]
39043923
#[inline]
39053924
#[rustc_inherit_overflow_checks]
3906-
pub fn pow(self, mut exp: u32) -> Self {
3925+
pub const fn pow(self, mut exp: u32) -> Self {
39073926
let mut base = self;
39083927
let mut acc = 1;
39093928

@@ -4014,7 +4033,8 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
40144033
// overflow cases it instead ends up returning the maximum value
40154034
// of the type, and can return 0 for 0.
40164035
#[inline]
4017-
fn one_less_than_next_power_of_two(self) -> Self {
4036+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
4037+
const fn one_less_than_next_power_of_two(self) -> Self {
40184038
if self <= 1 { return 0; }
40194039

40204040
let p = self - 1;
@@ -4042,10 +4062,11 @@ Basic usage:
40424062
assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
40434063
```"),
40444064
#[stable(feature = "rust1", since = "1.0.0")]
4065+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
40454066
#[inline]
4046-
pub fn next_power_of_two(self) -> Self {
4047-
// Call the trait to get overflow checks
4048-
ops::Add::add(self.one_less_than_next_power_of_two(), 1)
4067+
#[rustc_inherit_overflow_checks]
4068+
pub const fn next_power_of_two(self) -> Self {
4069+
self.one_less_than_next_power_of_two() + 1
40494070
}
40504071
}
40514072

@@ -4067,7 +4088,8 @@ $EndFeature, "
40674088
```"),
40684089
#[inline]
40694090
#[stable(feature = "rust1", since = "1.0.0")]
4070-
pub fn checked_next_power_of_two(self) -> Option<Self> {
4091+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
4092+
pub const fn checked_next_power_of_two(self) -> Option<Self> {
40714093
self.one_less_than_next_power_of_two().checked_add(1)
40724094
}
40734095
}
@@ -4091,7 +4113,8 @@ $EndFeature, "
40914113
```"),
40924114
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
40934115
reason = "needs decision on wrapping behaviour")]
4094-
pub fn wrapping_next_power_of_two(self) -> Self {
4116+
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
4117+
pub const fn wrapping_next_power_of_two(self) -> Self {
40954118
self.one_less_than_next_power_of_two().wrapping_add(1)
40964119
}
40974120
}
+37
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,48 @@
11
// run-pass
22

3+
#![feature(const_int_pow)]
4+
#![feature(wrapping_next_power_of_two)]
5+
36
const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
47
const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two();
58
const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two();
69

10+
const POW: u8 = 3u8.pow(5);
11+
12+
const CHECKED_POW_OK: Option<u8> = 3u8.checked_pow(5);
13+
const CHECKED_POW_OVERFLOW: Option<u8> = 3u8.checked_pow(6);
14+
15+
const WRAPPING_POW: u8 = 3u8.wrapping_pow(6);
16+
const OVERFLOWING_POW: (u8, bool) = 3u8.overflowing_pow(6);
17+
const SATURATING_POW: u8 = 3u8.saturating_pow(6);
18+
19+
const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two();
20+
21+
const CHECKED_NEXT_POWER_OF_TWO_OK: Option<u32> = 3u32.checked_next_power_of_two();
22+
const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option<u32> =
23+
u32::max_value().checked_next_power_of_two();
24+
25+
const WRAPPING_NEXT_POWER_OF_TWO: u32 =
26+
u32::max_value().wrapping_next_power_of_two();
27+
728
fn main() {
829
assert!(!IS_POWER_OF_TWO_A);
930
assert!(IS_POWER_OF_TWO_B);
1031
assert!(!IS_POWER_OF_TWO_C);
32+
33+
assert_eq!(POW, 243);
34+
35+
assert_eq!(CHECKED_POW_OK, Some(243));
36+
assert_eq!(CHECKED_POW_OVERFLOW, None);
37+
38+
assert_eq!(WRAPPING_POW, 217);
39+
assert_eq!(OVERFLOWING_POW, (217, true));
40+
assert_eq!(SATURATING_POW, u8::max_value());
41+
42+
assert_eq!(NEXT_POWER_OF_TWO, 4);
43+
44+
assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OK, Some(4));
45+
assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OVERFLOW, None);
46+
47+
assert_eq!(WRAPPING_NEXT_POWER_OF_TWO, 0);
1148
}

0 commit comments

Comments
 (0)