Skip to content

Commit 0673ba1

Browse files
committed
Add debug_assert_nounwrap to unchecked_{add,sub,neg,mul,shl,shr} methods
1 parent 6bdb8a4 commit 0673ba1

File tree

27 files changed

+620
-161
lines changed

27 files changed

+620
-161
lines changed

library/core/src/num/int_macros.rs

+57-22
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,14 @@ 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+
intrinsics::unchecked_add(self, rhs)
520+
}
516521
}
517522

518523
/// Checked addition with an unsigned integer. Computes `self + rhs`,
@@ -648,9 +653,14 @@ macro_rules! int_impl {
648653
#[inline(always)]
649654
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
650655
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) }
656+
debug_assert_nounwind!(
657+
!self.overflowing_sub(rhs).1,
658+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
659+
);
660+
// SAFETY: this is guaranteed to be safe by the caller.
661+
unsafe {
662+
intrinsics::unchecked_sub(self, rhs)
663+
}
654664
}
655665

656666
/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@@ -786,9 +796,14 @@ macro_rules! int_impl {
786796
#[inline(always)]
787797
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
788798
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) }
799+
debug_assert_nounwind!(
800+
!self.overflowing_mul(rhs).1,
801+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
802+
);
803+
// SAFETY: this is guaranteed to be safe by the caller.
804+
unsafe {
805+
intrinsics::unchecked_mul(self, rhs)
806+
}
792807
}
793808

794809
/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@@ -1125,9 +1140,15 @@ macro_rules! int_impl {
11251140
#[inline(always)]
11261141
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11271142
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) }
1143+
debug_assert_nounwind!(
1144+
!self.overflowing_neg().1,
1145+
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
1146+
);
1147+
// SAFETY: this is guaranteed to be safe by the caller.
1148+
unsafe {
1149+
let n = self;
1150+
intrinsics::unchecked_sub(0, n)
1151+
}
11311152
}
11321153

11331154
/// Strict negation. Computes `-self`, panicking if `self == MIN`.
@@ -1179,7 +1200,7 @@ macro_rules! int_impl {
11791200
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
11801201
#[must_use = "this returns the result of the operation, \
11811202
without modifying the original"]
1182-
#[inline]
1203+
#[inline(always)]
11831204
pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
11841205
let (a, b) = self.overflowing_shl(rhs);
11851206
if unlikely!(b) { None } else { Some(a) }
@@ -1241,10 +1262,15 @@ macro_rules! int_impl {
12411262
#[inline(always)]
12421263
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12431264
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1244-
// SAFETY: the caller must uphold the safety contract for
1245-
// `unchecked_shl`.
1265+
debug_assert_nounwind!(
1266+
rhs < Self::BITS,
1267+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1268+
);
1269+
// SAFETY: this is guaranteed to be safe by the caller.
12461270
// Any legal shift amount is losslessly representable in the self type.
1247-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1271+
unsafe {
1272+
intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs))
1273+
}
12481274
}
12491275

12501276
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -1262,7 +1288,7 @@ macro_rules! int_impl {
12621288
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
12631289
#[must_use = "this returns the result of the operation, \
12641290
without modifying the original"]
1265-
#[inline]
1291+
#[inline(always)]
12661292
pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
12671293
let (a, b) = self.overflowing_shr(rhs);
12681294
if unlikely!(b) { None } else { Some(a) }
@@ -1324,10 +1350,15 @@ macro_rules! int_impl {
13241350
#[inline(always)]
13251351
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13261352
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1327-
// SAFETY: the caller must uphold the safety contract for
1328-
// `unchecked_shr`.
1353+
debug_assert_nounwind!(
1354+
rhs < Self::BITS,
1355+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1356+
);
1357+
// SAFETY: this is guaranteed to be safe by the caller.
13291358
// Any legal shift amount is losslessly representable in the self type.
1330-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1359+
unsafe {
1360+
intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs))
1361+
}
13311362
}
13321363

13331364
/// Checked absolute value. Computes `self.abs()`, returning `None` if
@@ -1991,7 +2022,9 @@ macro_rules! int_impl {
19912022
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
19922023
// out of bounds
19932024
unsafe {
1994-
self.unchecked_shl(rhs & (Self::BITS - 1))
2025+
// FIXME: we can't optimize out the extra check here,
2026+
// so, we can't just call the method for now
2027+
intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1)))
19952028
}
19962029
}
19972030

@@ -2021,7 +2054,9 @@ macro_rules! int_impl {
20212054
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
20222055
// out of bounds
20232056
unsafe {
2024-
self.unchecked_shr(rhs & (Self::BITS - 1))
2057+
// FIXME: we can't optimize out the extra check here,
2058+
// so, we can't just call the method for now
2059+
intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1)))
20252060
}
20262061
}
20272062

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

+49-19
Original file line numberDiff line numberDiff line change
@@ -518,9 +518,15 @@ 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+
intrinsics::unchecked_add(self, rhs)
529+
}
524530
}
525531

526532
/// Checked addition with a signed integer. Computes `self + rhs`,
@@ -662,9 +668,14 @@ macro_rules! uint_impl {
662668
#[inline(always)]
663669
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
664670
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) }
671+
debug_assert_nounwind!(
672+
!self.overflowing_sub(rhs).1,
673+
concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
674+
);
675+
// SAFETY: this is guaranteed to be safe by the caller.
676+
unsafe {
677+
intrinsics::unchecked_sub(self, rhs)
678+
}
668679
}
669680

670681
/// Checked integer multiplication. Computes `self * rhs`, returning
@@ -744,9 +755,14 @@ macro_rules! uint_impl {
744755
#[inline(always)]
745756
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
746757
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) }
758+
debug_assert_nounwind!(
759+
!self.overflowing_mul(rhs).1,
760+
concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
761+
);
762+
// SAFETY: this is guaranteed to be safe by the caller.
763+
unsafe {
764+
intrinsics::unchecked_mul(self, rhs)
765+
}
750766
}
751767

752768
/// Checked integer division. Computes `self / rhs`, returning `None`
@@ -1239,7 +1255,7 @@ macro_rules! uint_impl {
12391255
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
12401256
#[must_use = "this returns the result of the operation, \
12411257
without modifying the original"]
1242-
#[inline]
1258+
#[inline(always)]
12431259
pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
12441260
let (a, b) = self.overflowing_shl(rhs);
12451261
if unlikely!(b) { None } else { Some(a) }
@@ -1301,10 +1317,15 @@ macro_rules! uint_impl {
13011317
#[inline(always)]
13021318
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13031319
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1304-
// SAFETY: the caller must uphold the safety contract for
1305-
// `unchecked_shl`.
1320+
debug_assert_nounwind!(
1321+
rhs < Self::BITS,
1322+
concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
1323+
);
1324+
// SAFETY: this is guaranteed to be safe by the caller.
13061325
// Any legal shift amount is losslessly representable in the self type.
1307-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1326+
unsafe {
1327+
intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs))
1328+
}
13081329
}
13091330

13101331
/// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -1322,7 +1343,7 @@ macro_rules! uint_impl {
13221343
#[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
13231344
#[must_use = "this returns the result of the operation, \
13241345
without modifying the original"]
1325-
#[inline]
1346+
#[inline(always)]
13261347
pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
13271348
let (a, b) = self.overflowing_shr(rhs);
13281349
if unlikely!(b) { None } else { Some(a) }
@@ -1384,10 +1405,15 @@ macro_rules! uint_impl {
13841405
#[inline(always)]
13851406
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13861407
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1387-
// SAFETY: the caller must uphold the safety contract for
1388-
// `unchecked_shr`.
1408+
debug_assert_nounwind!(
1409+
rhs < Self::BITS,
1410+
concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
1411+
);
1412+
// SAFETY: this is guaranteed to be safe by the caller.
13891413
// Any legal shift amount is losslessly representable in the self type.
1390-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1414+
unsafe {
1415+
intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs))
1416+
}
13911417
}
13921418

13931419
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
@@ -1878,7 +1904,9 @@ macro_rules! uint_impl {
18781904
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
18791905
// out of bounds
18801906
unsafe {
1881-
self.unchecked_shl(rhs & (Self::BITS - 1))
1907+
// FIXME: we can't optimize out the extra check here,
1908+
// so, we can't just call the method for now
1909+
intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1)))
18821910
}
18831911
}
18841912

@@ -1911,7 +1939,9 @@ macro_rules! uint_impl {
19111939
// SAFETY: the masking by the bitsize of the type ensures that we do not shift
19121940
// out of bounds
19131941
unsafe {
1914-
self.unchecked_shr(rhs & (Self::BITS - 1))
1942+
// FIXME: we can't optimize out the extra check here,
1943+
// so, we can't just call the method for now
1944+
intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs & (Self::BITS - 1)))
19151945
}
19161946
}
19171947

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

library/core/src/ptr/mut_ptr.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,7 @@ impl<T: ?Sized> *mut T {
11211121
#[must_use = "returns a new pointer rather than modifying its argument"]
11221122
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
11231123
// We could always go back to wrapping if unchecked becomes unacceptable
1124-
#[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
1124+
#[rustc_allow_const_fn_unstable(unchecked_math)]
11251125
#[inline(always)]
11261126
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11271127
pub const unsafe fn sub(self, count: usize) -> Self
@@ -1135,7 +1135,10 @@ impl<T: ?Sized> *mut T {
11351135
// SAFETY: the caller must uphold the safety contract for `offset`.
11361136
// Because the pointee is *not* a ZST, that means that `count` is
11371137
// at most `isize::MAX`, and thus the negation cannot overflow.
1138-
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
1138+
// FIXME: replacing unchecked_sub with unchecked_neg and replacing the
1139+
// unchecked_math flag with unchecked_neg will anger the UnstableInStable lint
1140+
// and I cannot for the life of me understand why
1141+
unsafe { self.offset(0isize.unchecked_sub(count as isize)) }
11391142
}
11401143
}
11411144

0 commit comments

Comments
 (0)