Skip to content

Commit d111a77

Browse files
committed
Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods
1 parent 547ace8 commit d111a77

File tree

6 files changed

+113
-44
lines changed

6 files changed

+113
-44
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+
(rhs: u32) => rhs < <$SelfT>::BITS
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+
(rhs: u32) => rhs < <$SelfT>::BITS
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+
(rhs: u32) => rhs < <$SelfT>::BITS
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+
(rhs: u32) => rhs < <$SelfT>::BITS
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

library/core/src/ops/index_range.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
1+
use crate::intrinsics::assert_unsafe_precondition;
22
use crate::iter::{FusedIterator, TrustedLen};
33
use crate::num::NonZeroUsize;
44

@@ -47,7 +47,7 @@ impl IndexRange {
4747
#[inline]
4848
pub const fn len(&self) -> usize {
4949
// SAFETY: By invariant, this cannot wrap
50-
unsafe { unchecked_sub(self.end, self.start) }
50+
unsafe { self.end.unchecked_sub(self.start) }
5151
}
5252

5353
/// # Safety
@@ -58,7 +58,7 @@ impl IndexRange {
5858

5959
let value = self.start;
6060
// SAFETY: The range isn't empty, so this cannot overflow
61-
self.start = unsafe { unchecked_add(value, 1) };
61+
self.start = unsafe { value.unchecked_add(1) };
6262
value
6363
}
6464

@@ -69,7 +69,7 @@ impl IndexRange {
6969
debug_assert!(self.start < self.end);
7070

7171
// SAFETY: The range isn't empty, so this cannot overflow
72-
let value = unsafe { unchecked_sub(self.end, 1) };
72+
let value = unsafe { self.end.unchecked_sub(1) };
7373
self.end = value;
7474
value
7575
}
@@ -84,7 +84,7 @@ impl IndexRange {
8484
let mid = if n <= self.len() {
8585
// SAFETY: We just checked that this will be between start and end,
8686
// and thus the addition cannot overflow.
87-
unsafe { unchecked_add(self.start, n) }
87+
unsafe { self.start.unchecked_add(n) }
8888
} else {
8989
self.end
9090
};
@@ -103,7 +103,7 @@ impl IndexRange {
103103
let mid = if n <= self.len() {
104104
// SAFETY: We just checked that this will be between start and end,
105105
// and thus the addition cannot overflow.
106-
unsafe { unchecked_sub(self.end, n) }
106+
unsafe { self.end.unchecked_sub(n) }
107107
} else {
108108
self.start
109109
};

library/core/src/ptr/const_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ impl<T: ?Sized> *const T {
10321032
// SAFETY: the caller must uphold the safety contract for `offset`.
10331033
// Because the pointee is *not* a ZST, that means that `count` is
10341034
// at most `isize::MAX`, and thus the negation cannot overflow.
1035-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1035+
unsafe { self.offset((count as isize).unchecked_neg()) }
10361036
}
10371037
}
10381038

library/core/src/ptr/mut_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ impl<T: ?Sized> *mut T {
11331133
// SAFETY: the caller must uphold the safety contract for `offset`.
11341134
// Because the pointee is *not* a ZST, that means that `count` is
11351135
// at most `isize::MAX`, and thus the negation cannot overflow.
1136-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1136+
unsafe { self.offset((count as isize).unchecked_neg()) }
11371137
}
11381138
}
11391139

library/core/src/slice/index.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use crate::intrinsics::assert_unsafe_precondition;
44
use crate::intrinsics::const_eval_select;
5-
use crate::intrinsics::unchecked_sub;
65
use crate::ops;
76
use crate::ptr;
87

@@ -380,7 +379,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
380379
[T](this: ops::Range<usize>, slice: *const [T]) =>
381380
this.end >= this.start && this.end <= slice.len()
382381
);
383-
let new_len = unchecked_sub(self.end, self.start);
382+
let new_len = self.end.unchecked_sub(self.start);
384383
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
385384
}
386385
}
@@ -395,7 +394,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
395394
[T](this: ops::Range<usize>, slice: *mut [T]) =>
396395
this.end >= this.start && this.end <= slice.len()
397396
);
398-
let new_len = unchecked_sub(self.end, self.start);
397+
let new_len = self.end.unchecked_sub(self.start);
399398
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
400399
}
401400
}

0 commit comments

Comments
 (0)