Skip to content

Commit 1d5d2ce

Browse files
committed
Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods
1 parent 146dafa commit 1d5d2ce

File tree

2 files changed

+103
-33
lines changed

2 files changed

+103
-33
lines changed

library/core/src/num/int_macros.rs

+56-18
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,15 @@ macro_rules! int_impl {
475475
#[inline(always)]
476476
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
477477
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
478-
// SAFETY: the caller must uphold the safety contract for
479-
// `unchecked_add`.
480-
unsafe { intrinsics::unchecked_add(self, rhs) }
478+
// SAFETY: this is guaranteed to be safe by the caller.
479+
unsafe {
480+
let lhs = self;
481+
intrinsics::assert_unsafe_precondition!(
482+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
483+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_add(rhs).1
484+
);
485+
intrinsics::unchecked_add(lhs, rhs)
486+
}
481487
}
482488

483489
/// Checked addition with an unsigned integer. Computes `self + rhs`,
@@ -543,9 +549,15 @@ macro_rules! int_impl {
543549
#[inline(always)]
544550
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
545551
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
546-
// SAFETY: the caller must uphold the safety contract for
547-
// `unchecked_sub`.
548-
unsafe { intrinsics::unchecked_sub(self, rhs) }
552+
// SAFETY: this is guaranteed to be safe by the caller.
553+
unsafe {
554+
let lhs = self;
555+
intrinsics::assert_unsafe_precondition!(
556+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
557+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_sub(rhs).1
558+
);
559+
intrinsics::unchecked_sub(lhs, rhs)
560+
}
549561
}
550562

551563
/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@@ -611,9 +623,15 @@ macro_rules! int_impl {
611623
#[inline(always)]
612624
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
613625
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
614-
// SAFETY: the caller must uphold the safety contract for
615-
// `unchecked_mul`.
616-
unsafe { intrinsics::unchecked_mul(self, rhs) }
626+
// SAFETY: this is guaranteed to be safe by the caller.
627+
unsafe {
628+
let lhs = self;
629+
intrinsics::assert_unsafe_precondition!(
630+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
631+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_mul(rhs).1
632+
);
633+
intrinsics::unchecked_mul(lhs, rhs)
634+
}
617635
}
618636

619637
/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@@ -760,9 +778,15 @@ macro_rules! int_impl {
760778
#[inline(always)]
761779
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
762780
pub const unsafe fn unchecked_neg(self) -> Self {
763-
// SAFETY: the caller must uphold the safety contract for
764-
// `unchecked_neg`.
765-
unsafe { intrinsics::unchecked_sub(0, self) }
781+
// SAFETY: this is guaranteed to be safe by the caller.
782+
unsafe {
783+
let n = self;
784+
intrinsics::assert_unsafe_precondition!(
785+
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
786+
(n: $SelfT) => !n.overflowing_neg().1
787+
);
788+
intrinsics::unchecked_sub(0, n)
789+
}
766790
}
767791

768792
/// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
@@ -807,10 +831,17 @@ macro_rules! int_impl {
807831
#[inline(always)]
808832
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
809833
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
810-
// SAFETY: the caller must uphold the safety contract for
811-
// `unchecked_shl`.
834+
// SAFETY: this is guaranteed to be safe by the caller.
812835
// Any legal shift amount is losslessly representable in the self type.
813-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
836+
unsafe {
837+
let lhs = self;
838+
intrinsics::assert_unsafe_precondition!(
839+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
840+
(lhs: $SelfT, rhs: u32) => !lhs.overflowing_shl(rhs).1
841+
);
842+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
843+
intrinsics::unchecked_shl(lhs, rhs)
844+
}
814845
}
815846

816847
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -855,10 +886,17 @@ macro_rules! int_impl {
855886
#[inline(always)]
856887
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
857888
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
858-
// SAFETY: the caller must uphold the safety contract for
859-
// `unchecked_shr`.
889+
// SAFETY: this is guaranteed to be safe by the caller.
860890
// Any legal shift amount is losslessly representable in the self type.
861-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
891+
unsafe {
892+
let lhs = self;
893+
intrinsics::assert_unsafe_precondition!(
894+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
895+
(lhs: $SelfT, rhs: u32) => !lhs.overflowing_shr(rhs).1
896+
);
897+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
898+
intrinsics::unchecked_shr(lhs, rhs)
899+
}
862900
}
863901

864902
/// Checked absolute value. Computes `self.abs()`, returning `None` if

library/core/src/num/uint_macros.rs

+47-15
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,15 @@ macro_rules! uint_impl {
483483
#[inline(always)]
484484
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
485485
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
486-
// SAFETY: the caller must uphold the safety contract for
487-
// `unchecked_add`.
488-
unsafe { intrinsics::unchecked_add(self, rhs) }
486+
// SAFETY: this is guaranteed to be safe by the caller.
487+
unsafe {
488+
let lhs = self;
489+
intrinsics::assert_unsafe_precondition!(
490+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
491+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_add(rhs).1
492+
);
493+
intrinsics::unchecked_add(lhs, rhs)
494+
}
489495
}
490496

491497
/// Checked addition with a signed integer. Computes `self + rhs`,
@@ -552,9 +558,15 @@ macro_rules! uint_impl {
552558
#[inline(always)]
553559
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
554560
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
555-
// SAFETY: the caller must uphold the safety contract for
556-
// `unchecked_sub`.
557-
unsafe { intrinsics::unchecked_sub(self, rhs) }
561+
// SAFETY: this is guaranteed to be safe by the caller.
562+
unsafe {
563+
let lhs = self;
564+
intrinsics::assert_unsafe_precondition!(
565+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
566+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_sub(rhs).1
567+
);
568+
intrinsics::unchecked_sub(lhs, rhs)
569+
}
558570
}
559571

560572
/// Checked integer multiplication. Computes `self * rhs`, returning
@@ -599,9 +611,15 @@ macro_rules! uint_impl {
599611
#[inline(always)]
600612
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
601613
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
602-
// SAFETY: the caller must uphold the safety contract for
603-
// `unchecked_mul`.
604-
unsafe { intrinsics::unchecked_mul(self, rhs) }
614+
// SAFETY: this is guaranteed to be safe by the caller.
615+
unsafe {
616+
let lhs = self;
617+
intrinsics::assert_unsafe_precondition!(
618+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
619+
(lhs: $SelfT, rhs: $SelfT) => !lhs.overflowing_mul(rhs).1
620+
);
621+
intrinsics::unchecked_mul(lhs, rhs)
622+
}
605623
}
606624

607625
/// Checked integer division. Computes `self / rhs`, returning `None`
@@ -936,10 +954,17 @@ macro_rules! uint_impl {
936954
#[inline(always)]
937955
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
938956
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
939-
// SAFETY: the caller must uphold the safety contract for
940-
// `unchecked_shl`.
957+
// SAFETY: this is guaranteed to be safe by the caller.
941958
// Any legal shift amount is losslessly representable in the self type.
942-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
959+
unsafe {
960+
let lhs = self;
961+
intrinsics::assert_unsafe_precondition!(
962+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
963+
(lhs: $SelfT, rhs: u32) => !lhs.overflowing_shl(rhs).1
964+
);
965+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
966+
intrinsics::unchecked_shl(lhs, rhs)
967+
}
943968
}
944969

945970
/// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -984,10 +1009,17 @@ macro_rules! uint_impl {
9841009
#[inline(always)]
9851010
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
9861011
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
987-
// SAFETY: the caller must uphold the safety contract for
988-
// `unchecked_shr`.
1012+
// SAFETY: this is guaranteed to be safe by the caller.
9891013
// Any legal shift amount is losslessly representable in the self type.
990-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1014+
unsafe {
1015+
let lhs = self;
1016+
intrinsics::assert_unsafe_precondition!(
1017+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1018+
(lhs: $SelfT, rhs: u32) => !lhs.overflowing_shl(rhs).1
1019+
);
1020+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
1021+
intrinsics::unchecked_shl(lhs, rhs)
1022+
}
9911023
}
9921024

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

0 commit comments

Comments
 (0)