Skip to content

Commit 0229426

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

18 files changed

+255
-57
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
#![feature(str_split_inclusive_remainder)]
193193
#![feature(str_split_remainder)]
194194
#![feature(strict_provenance)]
195+
#![feature(unchecked_neg)]
195196
#![feature(unchecked_shifts)]
196197
#![feature(utf16_extra)]
197198
#![feature(utf16_extra_const)]

library/core/src/num/int_macros.rs

+78-18
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,19 @@ macro_rules! int_impl {
488488
#[inline(always)]
489489
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
490490
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
491-
// SAFETY: the caller must uphold the safety contract for
492-
// `unchecked_add`.
493-
unsafe { intrinsics::unchecked_add(self, rhs) }
491+
assert_unsafe_precondition!(
492+
check_language_ub,
493+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
494+
(
495+
lhs: $SelfT = self,
496+
rhs: $SelfT = rhs,
497+
) => !lhs.overflowing_add(rhs).1,
498+
);
499+
500+
// SAFETY: this is guaranteed to be safe by the caller.
501+
unsafe {
502+
intrinsics::unchecked_add(self, rhs)
503+
}
494504
}
495505

496506
/// Checked addition with an unsigned integer. Computes `self + rhs`,
@@ -630,9 +640,19 @@ macro_rules! int_impl {
630640
#[inline(always)]
631641
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
632642
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
633-
// SAFETY: the caller must uphold the safety contract for
634-
// `unchecked_sub`.
635-
unsafe { intrinsics::unchecked_sub(self, rhs) }
643+
assert_unsafe_precondition!(
644+
check_language_ub,
645+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
646+
(
647+
lhs: $SelfT = self,
648+
rhs: $SelfT = rhs,
649+
) => !lhs.overflowing_sub(rhs).1,
650+
);
651+
652+
// SAFETY: this is guaranteed to be safe by the caller.
653+
unsafe {
654+
intrinsics::unchecked_sub(self, rhs)
655+
}
636656
}
637657

638658
/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@@ -772,9 +792,19 @@ macro_rules! int_impl {
772792
#[inline(always)]
773793
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
774794
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
775-
// SAFETY: the caller must uphold the safety contract for
776-
// `unchecked_mul`.
777-
unsafe { intrinsics::unchecked_mul(self, rhs) }
795+
assert_unsafe_precondition!(
796+
check_language_ub,
797+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
798+
(
799+
lhs: $SelfT = self,
800+
rhs: $SelfT = rhs,
801+
) => !lhs.overflowing_mul(rhs).1,
802+
);
803+
804+
// SAFETY: this is guaranteed to be safe by the caller.
805+
unsafe {
806+
intrinsics::unchecked_mul(self, rhs)
807+
}
778808
}
779809

780810
/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@@ -1111,9 +1141,18 @@ macro_rules! int_impl {
11111141
#[inline(always)]
11121142
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11131143
pub const unsafe fn unchecked_neg(self) -> Self {
1114-
// SAFETY: the caller must uphold the safety contract for
1115-
// `unchecked_neg`.
1116-
unsafe { intrinsics::unchecked_sub(0, self) }
1144+
assert_unsafe_precondition!(
1145+
check_language_ub,
1146+
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
1147+
(
1148+
lhs: $SelfT = self,
1149+
) => !lhs.overflowing_neg().1,
1150+
);
1151+
1152+
// SAFETY: this is guaranteed to be safe by the caller.
1153+
unsafe {
1154+
intrinsics::unchecked_sub(0, self)
1155+
}
11171156
}
11181157

11191158
/// Strict negation. Computes `-self`, panicking if `self == MIN`.
@@ -1235,9 +1274,19 @@ macro_rules! int_impl {
12351274
}
12361275
#[cfg(not(bootstrap))]
12371276
{
1238-
// SAFETY: the caller must uphold the safety contract for
1239-
// `unchecked_shl`.
1240-
unsafe { intrinsics::unchecked_shl(self, rhs) }
1277+
assert_unsafe_precondition!(
1278+
check_language_ub,
1279+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1280+
(
1281+
rhs: u32 = rhs,
1282+
bits: u32 = Self::BITS,
1283+
) => rhs < bits,
1284+
);
1285+
1286+
// SAFETY: this is guaranteed to be safe by the caller.
1287+
unsafe {
1288+
intrinsics::unchecked_shl(self, rhs)
1289+
}
12411290
}
12421291
}
12431292

@@ -1326,9 +1375,20 @@ macro_rules! int_impl {
13261375
}
13271376
#[cfg(not(bootstrap))]
13281377
{
1329-
// SAFETY: the caller must uphold the safety contract for
1330-
// `unchecked_shr`.
1331-
unsafe { intrinsics::unchecked_shr(self, rhs) }
1378+
assert_unsafe_precondition!(
1379+
check_language_ub,
1380+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1381+
(
1382+
rhs: u32 = rhs,
1383+
bits: u32 = Self::BITS,
1384+
) => rhs < bits,
1385+
);
1386+
1387+
// SAFETY: this is guaranteed to be safe by the caller.
1388+
// Any legal shift amount is losslessly representable in the self type.
1389+
unsafe {
1390+
intrinsics::unchecked_shr(self, rhs)
1391+
}
13321392
}
13331393
}
13341394

library/core/src/num/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::hint;
77
use crate::intrinsics;
88
use crate::mem;
99
use crate::str::FromStr;
10+
use crate::ub_checks::assert_unsafe_precondition;
1011

1112
// Used because the `?` operator is not allowed in a const context.
1213
macro_rules! try_opt {

library/core/src/num/uint_macros.rs

+66-15
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,19 @@ macro_rules! uint_impl {
495495
#[inline(always)]
496496
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
497497
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
498-
// SAFETY: the caller must uphold the safety contract for
499-
// `unchecked_add`.
500-
unsafe { intrinsics::unchecked_add(self, rhs) }
498+
assert_unsafe_precondition!(
499+
check_language_ub,
500+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
501+
(
502+
lhs: $SelfT = self,
503+
rhs: $SelfT = rhs,
504+
) => !lhs.overflowing_add(rhs).1,
505+
);
506+
507+
// SAFETY: this is guaranteed to be safe by the caller.
508+
unsafe {
509+
intrinsics::unchecked_add(self, rhs)
510+
}
501511
}
502512

503513
/// Checked addition with a signed integer. Computes `self + rhs`,
@@ -643,9 +653,19 @@ macro_rules! uint_impl {
643653
#[inline(always)]
644654
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
645655
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
646-
// SAFETY: the caller must uphold the safety contract for
647-
// `unchecked_sub`.
648-
unsafe { intrinsics::unchecked_sub(self, rhs) }
656+
assert_unsafe_precondition!(
657+
check_language_ub,
658+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
659+
(
660+
lhs: $SelfT = self,
661+
rhs: $SelfT = rhs,
662+
) => !lhs.overflowing_sub(rhs).1,
663+
);
664+
665+
// SAFETY: this is guaranteed to be safe by the caller.
666+
unsafe {
667+
intrinsics::unchecked_sub(self, rhs)
668+
}
649669
}
650670

651671
/// Checked integer multiplication. Computes `self * rhs`, returning
@@ -729,9 +749,19 @@ macro_rules! uint_impl {
729749
#[inline(always)]
730750
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
731751
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
732-
// SAFETY: the caller must uphold the safety contract for
733-
// `unchecked_mul`.
734-
unsafe { intrinsics::unchecked_mul(self, rhs) }
752+
assert_unsafe_precondition!(
753+
check_language_ub,
754+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
755+
(
756+
lhs: $SelfT = self,
757+
rhs: $SelfT = rhs,
758+
) => !lhs.overflowing_mul(rhs).1,
759+
);
760+
761+
// SAFETY: this is guaranteed to be safe by the caller.
762+
unsafe {
763+
intrinsics::unchecked_mul(self, rhs)
764+
}
735765
}
736766

737767
/// Checked integer division. Computes `self / rhs`, returning `None`
@@ -1294,9 +1324,19 @@ macro_rules! uint_impl {
12941324
}
12951325
#[cfg(not(bootstrap))]
12961326
{
1297-
// SAFETY: the caller must uphold the safety contract for
1298-
// `unchecked_shl`.
1299-
unsafe { intrinsics::unchecked_shl(self, rhs) }
1327+
assert_unsafe_precondition!(
1328+
check_language_ub,
1329+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1330+
(
1331+
rhs: u32 = rhs,
1332+
bits: u32 = Self::BITS,
1333+
) => rhs < bits,
1334+
);
1335+
1336+
// SAFETY: this is guaranteed to be safe by the caller.
1337+
unsafe {
1338+
intrinsics::unchecked_shl(self, rhs)
1339+
}
13001340
}
13011341
}
13021342

@@ -1385,9 +1425,20 @@ macro_rules! uint_impl {
13851425
}
13861426
#[cfg(not(bootstrap))]
13871427
{
1388-
// SAFETY: the caller must uphold the safety contract for
1389-
// `unchecked_shr`.
1390-
unsafe { intrinsics::unchecked_shr(self, rhs) }
1428+
assert_unsafe_precondition!(
1429+
check_language_ub,
1430+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1431+
(
1432+
rhs: u32 = rhs,
1433+
bits: u32 = Self::BITS,
1434+
) => rhs < bits,
1435+
);
1436+
1437+
// SAFETY: this is guaranteed to be safe by the caller.
1438+
// Any legal shift amount is losslessly representable in the self type.
1439+
unsafe {
1440+
intrinsics::unchecked_shr(self, rhs)
1441+
}
13911442
}
13921443
}
13931444

library/core/src/ops/index_range.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::intrinsics::{unchecked_add, unchecked_sub};
21
use crate::iter::{FusedIterator, TrustedLen};
32
use crate::num::NonZero;
43
use crate::ub_checks;
@@ -46,7 +45,7 @@ impl IndexRange {
4645
#[inline]
4746
pub const fn len(&self) -> usize {
4847
// SAFETY: By invariant, this cannot wrap
49-
unsafe { unchecked_sub(self.end, self.start) }
48+
unsafe { self.end.unchecked_sub(self.start) }
5049
}
5150

5251
/// # Safety
@@ -57,7 +56,7 @@ impl IndexRange {
5756

5857
let value = self.start;
5958
// SAFETY: The range isn't empty, so this cannot overflow
60-
self.start = unsafe { unchecked_add(value, 1) };
59+
self.start = unsafe { value.unchecked_add(1) };
6160
value
6261
}
6362

@@ -68,7 +67,7 @@ impl IndexRange {
6867
debug_assert!(self.start < self.end);
6968

7069
// SAFETY: The range isn't empty, so this cannot overflow
71-
let value = unsafe { unchecked_sub(self.end, 1) };
70+
let value = unsafe { self.end.unchecked_sub(1) };
7271
self.end = value;
7372
value
7473
}
@@ -83,7 +82,7 @@ impl IndexRange {
8382
let mid = if n <= self.len() {
8483
// SAFETY: We just checked that this will be between start and end,
8584
// and thus the addition cannot overflow.
86-
unsafe { unchecked_add(self.start, n) }
85+
unsafe { self.start.unchecked_add(n) }
8786
} else {
8887
self.end
8988
};
@@ -102,7 +101,7 @@ impl IndexRange {
102101
let mid = if n <= self.len() {
103102
// SAFETY: We just checked that this will be between start and end,
104103
// and thus the addition cannot overflow.
105-
unsafe { unchecked_sub(self.end, n) }
104+
unsafe { self.end.unchecked_sub(n) }
106105
} else {
107106
self.start
108107
};

library/core/src/ptr/const_ptr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ impl<T: ?Sized> *const T {
10291029
#[stable(feature = "pointer_methods", since = "1.26.0")]
10301030
#[must_use = "returns a new pointer rather than modifying its argument"]
10311031
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
1032+
#[rustc_allow_const_fn_unstable(unchecked_neg)]
10321033
#[inline(always)]
10331034
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
10341035
pub const unsafe fn sub(self, count: usize) -> Self
@@ -1042,7 +1043,7 @@ impl<T: ?Sized> *const T {
10421043
// SAFETY: the caller must uphold the safety contract for `offset`.
10431044
// Because the pointee is *not* a ZST, that means that `count` is
10441045
// at most `isize::MAX`, and thus the negation cannot overflow.
1045-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1046+
unsafe { self.offset((count as isize).unchecked_neg()) }
10461047
}
10471048
}
10481049

library/core/src/ptr/mut_ptr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,7 @@ impl<T: ?Sized> *mut T {
11181118
#[stable(feature = "pointer_methods", since = "1.26.0")]
11191119
#[must_use = "returns a new pointer rather than modifying its argument"]
11201120
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
1121+
#[rustc_allow_const_fn_unstable(unchecked_neg)]
11211122
#[inline(always)]
11221123
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11231124
pub const unsafe fn sub(self, count: usize) -> Self
@@ -1131,7 +1132,7 @@ impl<T: ?Sized> *mut T {
11311132
// SAFETY: the caller must uphold the safety contract for `offset`.
11321133
// Because the pointee is *not* a ZST, that means that `count` is
11331134
// at most `isize::MAX`, and thus the negation cannot overflow.
1134-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1135+
unsafe { self.offset((count as isize).unchecked_neg()) }
11351136
}
11361137
}
11371138

library/core/src/ptr/non_null.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ impl<T: ?Sized> NonNull<T> {
701701
/// ```
702702
#[unstable(feature = "non_null_convenience", issue = "117691")]
703703
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
704+
#[rustc_allow_const_fn_unstable(unchecked_neg)]
704705
#[must_use = "returns a new pointer rather than modifying its argument"]
705706
#[inline(always)]
706707
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -715,7 +716,7 @@ impl<T: ?Sized> NonNull<T> {
715716
// SAFETY: the caller must uphold the safety contract for `offset`.
716717
// Because the pointee is *not* a ZST, that means that `count` is
717718
// at most `isize::MAX`, and thus the negation cannot overflow.
718-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
719+
unsafe { self.offset((count as isize).unchecked_neg()) }
719720
}
720721
}
721722

library/core/src/slice/index.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Indexing implementations for `[T]`.
22
33
use crate::intrinsics::const_eval_select;
4-
use crate::intrinsics::unchecked_sub;
54
use crate::ops;
65
use crate::ptr;
76
use crate::ub_checks::assert_unsafe_precondition;
@@ -374,7 +373,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
374373
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
375374
// so the call to `add` is safe and the length calculation cannot overflow.
376375
unsafe {
377-
let new_len = unchecked_sub(self.end, self.start);
376+
let new_len = self.end.unchecked_sub(self.start);
378377
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
379378
}
380379
}
@@ -392,7 +391,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
392391
);
393392
// SAFETY: see comments for `get_unchecked` above.
394393
unsafe {
395-
let new_len = unchecked_sub(self.end, self.start);
394+
let new_len = self.end.unchecked_sub(self.start);
396395
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
397396
}
398397
}

0 commit comments

Comments
 (0)