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

Const-stabilize const_int_overflowing #57566

Merged
merged 2 commits into from
Jan 13, 2019
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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