Skip to content

Commit

Permalink
Auto merge of #57566 - Centril:const-stabilize-overflowing, r=alexreg
Browse files Browse the repository at this point in the history
Const-stabilize `const_int_overflowing`

Fixes #57237.

r? @alexreg
  • Loading branch information
bors committed Jan 13, 2019
2 parents 75a369c + b172e89 commit 5012d7f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
25 changes: 19 additions & 6 deletions src/libcore/num/bignum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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
Expand Down
56 changes: 34 additions & 22 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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)
}
}
Expand All @@ -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)
}
}
Expand Down Expand Up @@ -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)))
Expand All @@ -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)))
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -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)
}
}
Expand All @@ -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)
}

Expand Down Expand Up @@ -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)))
Expand All @@ -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)))
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 0 additions & 2 deletions src/test/run-pass/const-int-overflowing.rs
Original file line number Diff line number Diff line change
@@ -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);

Expand Down

0 comments on commit 5012d7f

Please sign in to comment.