diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a5f20d08e47be..8879112fcf0b9 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -114,6 +114,7 @@ #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] +#![cfg_attr(stage0, feature(const_let))] #![cfg_attr(stage0, feature(const_int_rotate))] #![feature(const_int_conversion)] #![feature(const_transmute)] diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 99a427ba15974..5326ef1e7c12e 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -46,25 +46,37 @@ macro_rules! impl_full_ops { ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => ( $( impl FullOps for $ty { + #[cfg(stage0)] fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) { - // this cannot overflow, the output is between 0 and 2*2^nbits - 1 - // FIXME will LLVM optimize this into ADC or similar??? + // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`. + // FIXME: will LLVM optimize this into ADC or similar? let (v, carry1) = unsafe { intrinsics::add_with_overflow(self, other) }; let (v, carry2) = unsafe { intrinsics::add_with_overflow(v, if carry {1} else {0}) }; (carry1 || carry2, v) } + #[cfg(not(stage0))] + fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) { + // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`. + // FIXME: will LLVM optimize this into ADC or similar? + let (v, carry1) = intrinsics::add_with_overflow(self, other); + let (v, carry2) = intrinsics::add_with_overflow(v, if carry {1} else {0}); + (carry1 || carry2, v) + } fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) { - // this cannot overflow, the output is between 0 and 2^nbits * (2^nbits - 1) + // This cannot overflow; + // the output is between `0` and `2^nbits * (2^nbits - 1)`. + // FIXME: will LLVM optimize this into ADC or similar? let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); ((v >> nbits) as $ty, v as $ty) } fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { - // this cannot overflow, the output is between 0 and 2^(2*nbits) - 1 + // This cannot overflow; + // the output is between `0` and `2^nbits * (2^nbits - 1)`. let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + (carry as $bigty); @@ -73,7 +85,7 @@ macro_rules! impl_full_ops { fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { debug_assert!(borrow < other); - // this cannot overflow, the dividend is between 0 and other * 2^nbits - 1 + // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`. let nbits = mem::size_of::<$ty>() * 8; let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); let rhs = other as $bigty; @@ -88,7 +100,8 @@ impl_full_ops! { u8: add(intrinsics::u8_add_with_overflow), mul/div(u16); u16: add(intrinsics::u16_add_with_overflow), mul/div(u32); u32: add(intrinsics::u32_add_with_overflow), mul/div(u64); -// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); // see RFC #521 for enabling this. + // See RFC #521 for enabling this. + // u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); } /// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7ff04410516a3..6827364c0f805 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1340,13 +1340,15 @@ assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($Sel "::MIN, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } } @@ -1369,13 +1371,15 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($Sel "::MAX, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } } @@ -1396,13 +1400,15 @@ assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } } @@ -1585,7 +1591,7 @@ assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -1609,7 +1615,7 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) @@ -3213,13 +3219,15 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } } @@ -3243,13 +3251,15 @@ assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } } @@ -3272,13 +3282,15 @@ $EndFeature, " /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); /// ``` #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + #[cfg(stage0)] let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, - rhs as $ActualT) + intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT) }; + #[cfg(not(stage0))] + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -3436,7 +3448,7 @@ Basic usage assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -3461,7 +3473,7 @@ Basic usage assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_int_overflowing")] + #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 41a042ebcb643..059b88a4d702a 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -374,6 +374,9 @@ fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool | "min_align_of" | "needs_drop" // Arithmetic: + | "add_with_overflow" // ~> .overflowing_add + | "sub_with_overflow" // ~> .overflowing_sub + | "mul_with_overflow" // ~> .overflowing_mul | "overflowing_add" // ~> .wrapping_add | "overflowing_sub" // ~> .wrapping_sub | "overflowing_mul" // ~> .wrapping_mul diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 04d18ff7aa372..9f323b9116d6f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -70,6 +70,7 @@ fn equate_intrinsic_type<'a, 'tcx>( pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { match intrinsic { "size_of" | "min_align_of" | "needs_drop" | + "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" diff --git a/src/test/run-pass/const-int-overflowing.rs b/src/test/run-pass/const-int-overflowing.rs index ae7ee5aa96e3e..289b1236cf1e2 100644 --- a/src/test/run-pass/const-int-overflowing.rs +++ b/src/test/run-pass/const-int-overflowing.rs @@ -1,5 +1,3 @@ -#![feature(const_int_overflowing)] - const ADD_A: (u32, bool) = 5u32.overflowing_add(2); const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1);