diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-02-20 10:49:12 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-20 10:49:12 +0100 |
| commit | d96951f5543869567e30ab1c63c0ac44d0d74c30 (patch) | |
| tree | 0820b7f10d8c88a997a1df000f7ffbfe02546019 | |
| parent | 588f00841b430b12b39fb75d778bd670df8c59f5 (diff) | |
| parent | 7fe5eaf7d8cb23ceb71d8e509be13d20ef836114 (diff) | |
| download | rust-d96951f5543869567e30ab1c63c0ac44d0d74c30.tar.gz rust-d96951f5543869567e30ab1c63c0ac44d0d74c30.zip | |
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.
| -rw-r--r-- | src/libcore/lib.rs | 3 | ||||
| -rw-r--r-- | src/libcore/num/mod.rs | 69 | ||||
| -rw-r--r-- | src/test/ui/consts/const-int-pow-rpass.rs | 37 |
3 files changed, 86 insertions, 23 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 12647fae900..bca96b77812 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -73,11 +73,14 @@ #![feature(const_ascii_ctype_on_intrinsics)] #![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)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 471ab966622..6f55e7c8be8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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 ) => { $( @@ -993,26 +1002,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) @@ -1180,10 +1190,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(), @@ -1523,10 +1534,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; @@ -1900,10 +1912,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; @@ -1949,11 +1962,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; @@ -3119,26 +3133,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) @@ -3234,10 +3249,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(), @@ -3527,10 +3543,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; @@ -3853,10 +3870,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; @@ -3899,11 +3917,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; @@ -4014,7 +4033,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; @@ -4042,10 +4062,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 } } @@ -4067,7 +4088,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) } } @@ -4091,7 +4113,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) } } diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs index 8e84a900605..b0fba19455b 100644 --- a/src/test/ui/consts/const-int-pow-rpass.rs +++ b/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); } |
