diff options
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/num/int_macros.rs | 508 | ||||
| -rw-r--r-- | library/core/src/num/mod.rs | 1 | ||||
| -rw-r--r-- | library/core/src/num/overflow_panic.rs | 47 |
4 files changed, 557 insertions, 0 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 921a0fb6a9f..44ba6c58c67 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -162,6 +162,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] +#![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] #![feature(const_type_id)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index fd01f1b2610..8b3f742bf91 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -454,6 +454,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer addition. Computes `self + rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. /// @@ -501,6 +533,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict addition with an unsigned integer. Computes `self + rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -522,6 +586,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer subtraction. Computes `self - rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_sub(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {overflow_panic::sub()} else {a} + } + /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. /// @@ -569,6 +665,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict subtraction with an unsigned integer. Computes `self - rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {overflow_panic::sub()} else {a} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -590,6 +718,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer multiplication. Computes `self * rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] + /// ``` + /// + /// ``` should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_mul(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {overflow_panic::mul()} else {a} + } + /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. /// @@ -642,6 +802,49 @@ macro_rules! int_impl { } } + /// Strict integer division. Computes `self / rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_div(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div(rhs); + if unlikely!(b) {overflow_panic::div()} else {a} + } + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, /// returning `None` if `rhs == 0` or the division results in overflow. /// @@ -668,6 +871,49 @@ macro_rules! int_impl { } } + /// Strict Euclidean division. Computes `self.div_euclid(rhs)`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div_euclid(rhs); + if unlikely!(b) {overflow_panic::div()} else {a} + } + /// Checked integer remainder. Computes `self % rhs`, returning `None` if /// `rhs == 0` or the division results in overflow. /// @@ -694,6 +940,48 @@ macro_rules! int_impl { } } + /// Strict integer remainder. Computes `self % rhs`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_rem(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem(rhs); + if unlikely!(b) {overflow_panic::rem()} else {a} + } + /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` /// if `rhs == 0` or the division results in overflow. /// @@ -720,6 +1008,48 @@ macro_rules! int_impl { } } + /// Strict Euclidean remainder. Computes `self.rem_euclid(rhs)`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem_euclid(rhs); + if unlikely!(b) {overflow_panic::rem()} else {a} + } + /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. /// /// # Examples @@ -765,6 +1095,37 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(0, self) } } + /// Strict negation. Computes `-self`, panicking if `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] + /// + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_neg(self) -> Self { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {overflow_panic::neg()} else {a} + } + /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger /// than or equal to the number of bits in `self`. /// @@ -786,6 +1147,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger + /// than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shl(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {overflow_panic::shl()} else {a} + } + /// Unchecked shift left. Computes `self << rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -834,6 +1227,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// larger than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shr(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {overflow_panic::shr()} else {a} + } + /// Unchecked shift right. Computes `self >> rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -885,6 +1310,41 @@ macro_rules! int_impl { } } + /// Strict absolute value. Computes `self.abs()`, panicking if + /// `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_abs(self) -> Self { + if self.is_negative() { + self.strict_neg() + } else { + self + } + } + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if /// overflow occurred. /// @@ -923,6 +1383,54 @@ macro_rules! int_impl { acc.checked_mul(base) } + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.strict_mul(base); + } + exp /= 2; + base = base.strict_mul(base); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.strict_mul(base) + } + /// Returns the square root of the number, rounded down. /// /// Returns `None` if `self` is negative. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 2a0b31404f0..96de7673c6f 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -44,6 +44,7 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod nonzero; +mod overflow_panic; mod saturating; mod wrapping; diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs new file mode 100644 index 00000000000..b941fdb212a --- /dev/null +++ b/library/core/src/num/overflow_panic.rs @@ -0,0 +1,47 @@ +#[cold] +#[track_caller] +pub const fn add() -> ! { + panic!("attempt to add with overflow") +} + +#[cold] +#[track_caller] +pub const fn sub() -> ! { + panic!("attempt to subtract with overflow") +} + +#[cold] +#[track_caller] +pub const fn mul() -> ! { + panic!("attempt to multiply with overflow") +} + +#[cold] +#[track_caller] +pub const fn div() -> ! { + panic!("attempt to divide with overflow") +} + +#[cold] +#[track_caller] +pub const fn rem() -> ! { + panic!("attempt to calculate the remainder with overflow") +} + +#[cold] +#[track_caller] +pub const fn neg() -> ! { + panic!("attempt to negate with overflow") +} + +#[cold] +#[track_caller] +pub const fn shr() -> ! { + panic!("attempt to shift right with overflow") +} + +#[cold] +#[track_caller] +pub const fn shl() -> ! { + panic!("attempt to shift left with overflow") +} |
