Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make integer exponentiation methods unstably const #68978

Merged
merged 4 commits into from Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libcore/lib.rs
Expand Up @@ -72,11 +72,14 @@
#![feature(concat_idents)]
#![feature(const_alloc_layout)]
#![feature(const_if_match)]
#![feature(const_loop)]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_overflowing_int_methods)]
#![feature(const_saturating_int_methods)]
#![feature(const_int_unchecked_arith)]
#![feature(const_int_pow)]
#![feature(constctlz)]
#![feature(const_panic)]
#![feature(const_fn_union)]
#![feature(const_generics)]
Expand Down
69 changes: 46 additions & 23 deletions src/libcore/num/mod.rs
Expand Up @@ -8,9 +8,18 @@ use crate::convert::Infallible;
use crate::fmt;
use crate::intrinsics;
use crate::mem;
use crate::ops;
use crate::str::FromStr;

// Used because the `?` operator is not allowed in a const context.
macro_rules! try_opt {
($e:expr) => {
match $e {
Some(x) => x,
None => return None,
}
};
}

macro_rules! impl_nonzero_fmt {
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
$(
Expand Down Expand Up @@ -992,26 +1001,27 @@ $EndFeature, "
```"),

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

while exp > 1 {
if (exp & 1) == 1 {
acc = acc.checked_mul(base)?;
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = base.checked_mul(base)?;
base = try_opt!(base.checked_mul(base));
}

// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.checked_mul(base)?;
acc = try_opt!(acc.checked_mul(base));
}

Some(acc)
Expand Down Expand Up @@ -1179,10 +1189,11 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
pub const fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Some(x) => x,
None if self < 0 && exp % 2 == 1 => Self::min_value(),
Expand Down Expand Up @@ -1522,10 +1533,11 @@ assert_eq!(3i8.wrapping_pow(6), -39);",
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc: Self = 1;

Expand Down Expand Up @@ -1899,10 +1911,11 @@ assert_eq!(3i8.overflowing_pow(5), (-13, true));",
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
Expand Down Expand Up @@ -1948,11 +1961,12 @@ assert_eq!(x.pow(5), 32);",
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn pow(self, mut exp: u32) -> Self {
pub const fn pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc = 1;

Expand Down Expand Up @@ -3118,26 +3132,27 @@ Basic usage:
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
let mut base = self;
let mut acc: Self = 1;

while exp > 1 {
if (exp & 1) == 1 {
acc = acc.checked_mul(base)?;
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = base.checked_mul(base)?;
base = try_opt!(base.checked_mul(base));
}

// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.checked_mul(base)?;
acc = try_opt!(acc.checked_mul(base));
}

Some(acc)
Expand Down Expand Up @@ -3233,10 +3248,11 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
pub const fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Some(x) => x,
None => Self::max_value(),
Expand Down Expand Up @@ -3526,10 +3542,11 @@ Basic usage:
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc: Self = 1;

Expand Down Expand Up @@ -3852,10 +3869,11 @@ Basic usage:
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
Expand Down Expand Up @@ -3898,11 +3916,12 @@ Basic usage:
", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn pow(self, mut exp: u32) -> Self {
pub const fn pow(self, mut exp: u32) -> Self {
let mut base = self;
let mut acc = 1;

Expand Down Expand Up @@ -4013,7 +4032,8 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
// overflow cases it instead ends up returning the maximum value
// of the type, and can return 0 for 0.
#[inline]
fn one_less_than_next_power_of_two(self) -> Self {
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
const fn one_less_than_next_power_of_two(self) -> Self {
if self <= 1 { return 0; }

let p = self - 1;
Expand Down Expand Up @@ -4041,10 +4061,11 @@ Basic usage:
assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
#[inline]
pub fn next_power_of_two(self) -> Self {
// Call the trait to get overflow checks
ops::Add::add(self.one_less_than_next_power_of_two(), 1)
#[rustc_inherit_overflow_checks]
pub const fn next_power_of_two(self) -> Self {
self.one_less_than_next_power_of_two() + 1
}
}

Expand All @@ -4066,7 +4087,8 @@ $EndFeature, "
```"),
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn checked_next_power_of_two(self) -> Option<Self> {
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
pub const fn checked_next_power_of_two(self) -> Option<Self> {
self.one_less_than_next_power_of_two().checked_add(1)
}
}
Expand All @@ -4090,7 +4112,8 @@ $EndFeature, "
```"),
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
reason = "needs decision on wrapping behaviour")]
pub fn wrapping_next_power_of_two(self) -> Self {
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
pub const fn wrapping_next_power_of_two(self) -> Self {
self.one_less_than_next_power_of_two().wrapping_add(1)
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/test/ui/consts/const-int-pow-rpass.rs
@@ -1,11 +1,48 @@
// run-pass

#![feature(const_int_pow)]
#![feature(wrapping_next_power_of_two)]

const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two();
const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two();

const POW: u8 = 3u8.pow(5);

const CHECKED_POW_OK: Option<u8> = 3u8.checked_pow(5);
const CHECKED_POW_OVERFLOW: Option<u8> = 3u8.checked_pow(6);

const WRAPPING_POW: u8 = 3u8.wrapping_pow(6);
const OVERFLOWING_POW: (u8, bool) = 3u8.overflowing_pow(6);
const SATURATING_POW: u8 = 3u8.saturating_pow(6);

const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two();

const CHECKED_NEXT_POWER_OF_TWO_OK: Option<u32> = 3u32.checked_next_power_of_two();
const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option<u32> =
u32::max_value().checked_next_power_of_two();

const WRAPPING_NEXT_POWER_OF_TWO: u32 =
u32::max_value().wrapping_next_power_of_two();

fn main() {
assert!(!IS_POWER_OF_TWO_A);
assert!(IS_POWER_OF_TWO_B);
assert!(!IS_POWER_OF_TWO_C);

assert_eq!(POW, 243);

assert_eq!(CHECKED_POW_OK, Some(243));
assert_eq!(CHECKED_POW_OVERFLOW, None);

assert_eq!(WRAPPING_POW, 217);
assert_eq!(OVERFLOWING_POW, (217, true));
assert_eq!(SATURATING_POW, u8::max_value());

assert_eq!(NEXT_POWER_OF_TWO, 4);

assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OK, Some(4));
assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OVERFLOW, None);

assert_eq!(WRAPPING_NEXT_POWER_OF_TWO, 0);
}