Skip to content

Commit

Permalink
Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr}…
Browse files Browse the repository at this point in the history
… methods
  • Loading branch information
clarfonthey committed Nov 1, 2023
1 parent 146dafa commit 0a443eb
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 33 deletions.
74 changes: 56 additions & 18 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,15 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_add`.
unsafe { intrinsics::unchecked_add(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_add(rhs).1
);
intrinsics::unchecked_add(lhs, rhs)
}
}

/// Checked addition with an unsigned integer. Computes `self + rhs`,
Expand Down Expand Up @@ -543,9 +549,15 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_sub`.
unsafe { intrinsics::unchecked_sub(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_sub(rhs).1
);
intrinsics::unchecked_sub(lhs, rhs)
}
}

/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
Expand Down Expand Up @@ -611,9 +623,15 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_mul`.
unsafe { intrinsics::unchecked_mul(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_mul(rhs).1
);
intrinsics::unchecked_mul(lhs, rhs)
}
}

/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
Expand Down Expand Up @@ -760,9 +778,15 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_neg(self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_neg`.
unsafe { intrinsics::unchecked_sub(0, self) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let n = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
(n: $SelfT) => !n.overflowing_neg().1
);
intrinsics::unchecked_sub(0, n)
}
}

/// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
Expand Down Expand Up @@ -807,10 +831,17 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
// SAFETY: this is guaranteed to be safe by the caller.
// Any legal shift amount is losslessly representable in the self type.
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
unsafe {
let lhs = self;
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_shl(rhs).1
);
intrinsics::unchecked_shl(lhs, rhs)
}
}

/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
Expand Down Expand Up @@ -855,10 +886,17 @@ macro_rules! int_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
// SAFETY: this is guaranteed to be safe by the caller.
// Any legal shift amount is losslessly representable in the self type.
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
unsafe {
let lhs = self;
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_shr(rhs).1
);
intrinsics::unchecked_shr(lhs, rhs)
}
}

/// Checked absolute value. Computes `self.abs()`, returning `None` if
Expand Down
62 changes: 47 additions & 15 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,15 @@ macro_rules! uint_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_add`.
unsafe { intrinsics::unchecked_add(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_add(rhs).1
);
intrinsics::unchecked_add(lhs, rhs)
}
}

/// Checked addition with a signed integer. Computes `self + rhs`,
Expand Down Expand Up @@ -552,9 +558,15 @@ macro_rules! uint_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_sub`.
unsafe { intrinsics::unchecked_sub(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_sub(rhs).1
);
intrinsics::unchecked_sub(lhs, rhs)
}
}

/// Checked integer multiplication. Computes `self * rhs`, returning
Expand Down Expand Up @@ -599,9 +611,15 @@ macro_rules! uint_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_mul`.
unsafe { intrinsics::unchecked_mul(self, rhs) }
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
let lhs = self;
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_mul(rhs).1
);
intrinsics::unchecked_mul(lhs, rhs)
}
}

/// Checked integer division. Computes `self / rhs`, returning `None`
Expand Down Expand Up @@ -936,10 +954,17 @@ macro_rules! uint_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
// SAFETY: this is guaranteed to be safe by the caller.
// Any legal shift amount is losslessly representable in the self type.
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
unsafe {
let lhs = self;
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_shl(rhs).1
);
intrinsics::unchecked_shl(lhs, rhs)
}
}

/// Checked shift right. Computes `self >> rhs`, returning `None`
Expand Down Expand Up @@ -984,10 +1009,17 @@ macro_rules! uint_impl {
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
// SAFETY: this is guaranteed to be safe by the caller.
// Any legal shift amount is losslessly representable in the self type.
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
unsafe {
let lhs = self;
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
intrinsics::assert_unsafe_precondition!(
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_shl(rhs).1
);
intrinsics::unchecked_shl(lhs, rhs)
}
}

/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
Expand Down

0 comments on commit 0a443eb

Please sign in to comment.