Skip to content

Commit c6787ca

Browse files
committed
Add debug_assert_nounwrap to unchecked_{add,sub,neg,mul,shl,shr} methods
1 parent 397937d commit c6787ca

26 files changed

+734
-158
lines changed

library/core/src/num/int_macros.rs

+66-22
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,15 @@ macro_rules! int_impl {
510510
#[inline(always)]
511511
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
512512
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
513-
// SAFETY: the caller must uphold the safety contract for
514-
// `unchecked_add`.
515-
unsafe { intrinsics::unchecked_add(self, rhs) }
513+
debug_assert_nounwind!(
514+
!self.overflowing_add(rhs).1,
515+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
516+
);
517+
// SAFETY: this is guaranteed to be safe by the caller.
518+
unsafe {
519+
let lhs = self;
520+
intrinsics::unchecked_add(lhs, rhs)
521+
}
516522
}
517523

518524
/// Checked addition with an unsigned integer. Computes `self + rhs`,
@@ -648,9 +654,15 @@ macro_rules! int_impl {
648654
#[inline(always)]
649655
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
650656
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
651-
// SAFETY: the caller must uphold the safety contract for
652-
// `unchecked_sub`.
653-
unsafe { intrinsics::unchecked_sub(self, rhs) }
657+
debug_assert_nounwind!(
658+
!self.overflowing_sub(rhs).1,
659+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
660+
);
661+
// SAFETY: this is guaranteed to be safe by the caller.
662+
unsafe {
663+
let lhs = self;
664+
intrinsics::unchecked_sub(lhs, rhs)
665+
}
654666
}
655667

656668
/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@@ -786,9 +798,15 @@ macro_rules! int_impl {
786798
#[inline(always)]
787799
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
788800
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
789-
// SAFETY: the caller must uphold the safety contract for
790-
// `unchecked_mul`.
791-
unsafe { intrinsics::unchecked_mul(self, rhs) }
801+
debug_assert_nounwind!(
802+
!self.overflowing_mul(rhs).1,
803+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
804+
);
805+
// SAFETY: this is guaranteed to be safe by the caller.
806+
unsafe {
807+
let lhs = self;
808+
intrinsics::unchecked_mul(lhs, rhs)
809+
}
792810
}
793811

794812
/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@@ -1125,9 +1143,15 @@ macro_rules! int_impl {
11251143
#[inline(always)]
11261144
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11271145
pub const unsafe fn unchecked_neg(self) -> Self {
1128-
// SAFETY: the caller must uphold the safety contract for
1129-
// `unchecked_neg`.
1130-
unsafe { intrinsics::unchecked_sub(0, self) }
1146+
debug_assert_nounwind!(
1147+
!self.overflowing_neg().1,
1148+
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
1149+
);
1150+
// SAFETY: this is guaranteed to be safe by the caller.
1151+
unsafe {
1152+
let n = self;
1153+
intrinsics::unchecked_sub(0, n)
1154+
}
11311155
}
11321156

11331157
/// Strict negation. Computes `-self`, panicking if `self == MIN`.
@@ -1179,7 +1203,7 @@ macro_rules! int_impl {
11791203
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
11801204
#[must_use = "this returns the result of the operation, \
11811205
without modifying the original"]
1182-
#[inline]
1206+
#[inline(always)]
11831207
pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
11841208
let (a, b) = self.overflowing_shl(rhs);
11851209
if unlikely!(b) { None } else { Some(a) }
@@ -1241,10 +1265,17 @@ macro_rules! int_impl {
12411265
#[inline(always)]
12421266
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12431267
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1244-
// SAFETY: the caller must uphold the safety contract for
1245-
// `unchecked_shl`.
1268+
debug_assert_nounwind!(
1269+
rhs < Self::BITS,
1270+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1271+
);
1272+
// SAFETY: this is guaranteed to be safe by the caller.
12461273
// Any legal shift amount is losslessly representable in the self type.
1247-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1274+
unsafe {
1275+
let lhs = self;
1276+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
1277+
intrinsics::unchecked_shl(lhs, rhs)
1278+
}
12481279
}
12491280

12501281
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -1262,7 +1293,7 @@ macro_rules! int_impl {
12621293
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
12631294
#[must_use = "this returns the result of the operation, \
12641295
without modifying the original"]
1265-
#[inline]
1296+
#[inline(always)]
12661297
pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
12671298
let (a, b) = self.overflowing_shr(rhs);
12681299
if unlikely!(b) { None } else { Some(a) }
@@ -1324,10 +1355,17 @@ macro_rules! int_impl {
13241355
#[inline(always)]
13251356
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13261357
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1327-
// SAFETY: the caller must uphold the safety contract for
1328-
// `unchecked_shr`.
1358+
debug_assert_nounwind!(
1359+
rhs < Self::BITS,
1360+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1361+
);
1362+
// SAFETY: this is guaranteed to be safe by the caller.
13291363
// Any legal shift amount is losslessly representable in the self type.
1330-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1364+
unsafe {
1365+
let lhs = self;
1366+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
1367+
intrinsics::unchecked_shr(lhs, rhs)
1368+
}
13311369
}
13321370

13331371
/// Checked absolute value. Computes `self.abs()`, returning `None` if
@@ -1991,7 +2029,10 @@ macro_rules! int_impl {
19912029
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
19922030
// out of bounds
19932031
unsafe {
1994-
self.unchecked_shl(rhs & (Self::BITS - 1))
2032+
// FIXME: we can't optimize out the extra check here,
2033+
// so, we can't just call the method for now
2034+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1));
2035+
intrinsics::unchecked_shl(self, rhs)
19952036
}
19962037
}
19972038

@@ -2021,7 +2062,10 @@ macro_rules! int_impl {
20212062
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
20222063
// out of bounds
20232064
unsafe {
2024-
self.unchecked_shr(rhs & (Self::BITS - 1))
2065+
// FIXME: we can't optimize out the extra check here,
2066+
// so, we can't just call the method for now
2067+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1));
2068+
intrinsics::unchecked_shr(self, rhs)
20252069
}
20262070
}
20272071

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::ops::{Add, Mul, Sub};
10+
use crate::panic::debug_assert_nounwind;
1011
use crate::str::FromStr;
1112

1213
// Used because the `?` operator is not allowed in a const context.

library/core/src/num/uint_macros.rs

+58-19
Original file line numberDiff line numberDiff line change
@@ -518,9 +518,16 @@ macro_rules! uint_impl {
518518
#[inline(always)]
519519
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
520520
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
521-
// SAFETY: the caller must uphold the safety contract for
522-
// `unchecked_add`.
523-
unsafe { intrinsics::unchecked_add(self, rhs) }
521+
debug_assert_nounwind!(
522+
!self.overflowing_add(rhs).1,
523+
concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
524+
);
525+
526+
// SAFETY: this is guaranteed to be safe by the caller.
527+
unsafe {
528+
let lhs = self;
529+
intrinsics::unchecked_add(lhs, rhs)
530+
}
524531
}
525532

526533
/// Checked addition with a signed integer. Computes `self + rhs`,
@@ -662,9 +669,15 @@ macro_rules! uint_impl {
662669
#[inline(always)]
663670
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
664671
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
665-
// SAFETY: the caller must uphold the safety contract for
666-
// `unchecked_sub`.
667-
unsafe { intrinsics::unchecked_sub(self, rhs) }
672+
debug_assert_nounwind!(
673+
!self.overflowing_sub(rhs).1,
674+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
675+
);
676+
// SAFETY: this is guaranteed to be safe by the caller.
677+
unsafe {
678+
let lhs = self;
679+
intrinsics::unchecked_sub(lhs, rhs)
680+
}
668681
}
669682

670683
/// Checked integer multiplication. Computes `self * rhs`, returning
@@ -744,9 +757,15 @@ macro_rules! uint_impl {
744757
#[inline(always)]
745758
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
746759
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
747-
// SAFETY: the caller must uphold the safety contract for
748-
// `unchecked_mul`.
749-
unsafe { intrinsics::unchecked_mul(self, rhs) }
760+
debug_assert_nounwind!(
761+
!self.overflowing_mul(rhs).1,
762+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
763+
);
764+
// SAFETY: this is guaranteed to be safe by the caller.
765+
unsafe {
766+
let lhs = self;
767+
intrinsics::unchecked_mul(lhs, rhs)
768+
}
750769
}
751770

752771
/// Checked integer division. Computes `self / rhs`, returning `None`
@@ -1239,7 +1258,7 @@ macro_rules! uint_impl {
12391258
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
12401259
#[must_use = "this returns the result of the operation, \
12411260
without modifying the original"]
1242-
#[inline]
1261+
#[inline(always)]
12431262
pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
12441263
let (a, b) = self.overflowing_shl(rhs);
12451264
if unlikely!(b) { None } else { Some(a) }
@@ -1301,10 +1320,17 @@ macro_rules! uint_impl {
13011320
#[inline(always)]
13021321
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13031322
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1304-
// SAFETY: the caller must uphold the safety contract for
1305-
// `unchecked_shl`.
1323+
debug_assert_nounwind!(
1324+
rhs < Self::BITS,
1325+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1326+
);
1327+
// SAFETY: this is guaranteed to be safe by the caller.
13061328
// Any legal shift amount is losslessly representable in the self type.
1307-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1329+
unsafe {
1330+
let lhs = self;
1331+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
1332+
intrinsics::unchecked_shl(lhs, rhs)
1333+
}
13081334
}
13091335

13101336
/// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -1322,7 +1348,7 @@ macro_rules! uint_impl {
13221348
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
13231349
#[must_use = "this returns the result of the operation, \
13241350
without modifying the original"]
1325-
#[inline]
1351+
#[inline(always)]
13261352
pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
13271353
let (a, b) = self.overflowing_shr(rhs);
13281354
if unlikely!(b) { None } else { Some(a) }
@@ -1384,10 +1410,17 @@ macro_rules! uint_impl {
13841410
#[inline(always)]
13851411
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13861412
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1387-
// SAFETY: the caller must uphold the safety contract for
1388-
// `unchecked_shr`.
1413+
debug_assert_nounwind!(
1414+
rhs < Self::BITS,
1415+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1416+
);
1417+
// SAFETY: this is guaranteed to be safe by the caller.
13891418
// Any legal shift amount is losslessly representable in the self type.
1390-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1419+
unsafe {
1420+
let lhs = self;
1421+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs);
1422+
intrinsics::unchecked_shr(lhs, rhs)
1423+
}
13911424
}
13921425

13931426
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
@@ -1878,7 +1911,10 @@ macro_rules! uint_impl {
18781911
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
18791912
// out of bounds
18801913
unsafe {
1881-
self.unchecked_shl(rhs & (Self::BITS - 1))
1914+
// FIXME: we can't optimize out the extra check here,
1915+
// so, we can't just call the method for now
1916+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1));
1917+
intrinsics::unchecked_shl(self, rhs)
18821918
}
18831919
}
18841920

@@ -1911,7 +1947,10 @@ macro_rules! uint_impl {
19111947
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
19121948
// out of bounds
19131949
unsafe {
1914-
self.unchecked_shr(rhs & (Self::BITS - 1))
1950+
// FIXME: we can't optimize out the extra check here,
1951+
// so, we can't just call the method for now
1952+
let rhs = conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1));
1953+
intrinsics::unchecked_shr(self, rhs)
19151954
}
19161955
}
19171956

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

@@ -44,7 +43,7 @@ impl IndexRange {
4443
#[inline]
4544
pub const fn len(&self) -> usize {
4645
// SAFETY: By invariant, this cannot wrap
47-
unsafe { unchecked_sub(self.end, self.start) }
46+
unsafe { self.end.unchecked_sub(self.start) }
4847
}
4948

5049
/// # Safety
@@ -55,7 +54,7 @@ impl IndexRange {
5554

5655
let value = self.start;
5756
// SAFETY: The range isn't empty, so this cannot overflow
58-
self.start = unsafe { unchecked_add(value, 1) };
57+
self.start = unsafe { value.unchecked_add(1) };
5958
value
6059
}
6160

@@ -66,7 +65,7 @@ impl IndexRange {
6665
debug_assert!(self.start < self.end);
6766

6867
// SAFETY: The range isn't empty, so this cannot overflow
69-
let value = unsafe { unchecked_sub(self.end, 1) };
68+
let value = unsafe { self.end.unchecked_sub(1) };
7069
self.end = value;
7170
value
7271
}
@@ -81,7 +80,7 @@ impl IndexRange {
8180
let mid = if n <= self.len() {
8281
// SAFETY: We just checked that this will be between start and end,
8382
// and thus the addition cannot overflow.
84-
unsafe { unchecked_add(self.start, n) }
83+
unsafe { self.start.unchecked_add(n) }
8584
} else {
8685
self.end
8786
};
@@ -100,7 +99,7 @@ impl IndexRange {
10099
let mid = if n <= self.len() {
101100
// SAFETY: We just checked that this will be between start and end,
102101
// and thus the addition cannot overflow.
103-
unsafe { unchecked_sub(self.end, n) }
102+
unsafe { self.end.unchecked_sub(n) }
104103
} else {
105104
self.start
106105
};

library/core/src/panic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub macro debug_assert_nounwind {
167167
}
168168
}
169169
},
170-
($cond:expr, $message:expr) => {
170+
($cond:expr, $message:expr $(,)?) => {
171171
if $crate::intrinsics::debug_assertions() {
172172
if !$cond {
173173
$crate::panicking::panic_nounwind($message);

library/core/src/ptr/const_ptr.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1021,8 +1021,8 @@ impl<T: ?Sized> *const T {
10211021
#[must_use = "returns a new pointer rather than modifying its argument"]
10221022
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
10231023
// We could always go back to wrapping if unchecked becomes unacceptable
1024-
#[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
10251024
#[inline(always)]
1025+
#[rustc_allow_const_fn_unstable(unchecked_math)]
10261026
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
10271027
pub const unsafe fn sub(self, count: usize) -> Self
10281028
where
@@ -1035,7 +1035,10 @@ impl<T: ?Sized> *const T {
10351035
// SAFETY: the caller must uphold the safety contract for `offset`.
10361036
// Because the pointee is *not* a ZST, that means that `count` is
10371037
// at most `isize::MAX`, and thus the negation cannot overflow.
1038-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1038+
// FIXME: replacing unchecked_sub with unchecked_neg and replacing the
1039+
// unchecked_math flag with unchecked_neg will anger the UnstableInStable lint
1040+
// and I cannot for the life of me understand why
1041+
unsafe { self.offset(0isize.unchecked_sub(count as isize)) }
10391042
}
10401043
}
10411044

0 commit comments

Comments
 (0)