Skip to content

Commit 8561678

Browse files
committed
Expand precondition checks and improve get_unchecked errors
1 parent 1a648b3 commit 8561678

8 files changed

+208
-299
lines changed

library/core/src/panic.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,25 @@ pub macro unreachable_2021 {
146146
/// not compromise unwind safety.
147147
#[doc(hidden)]
148148
#[unstable(feature = "panic_internals", issue = "none")]
149-
#[allow_internal_unstable(panic_internals, const_format_args)]
149+
#[allow_internal_unstable(panic_internals, const_format_args, delayed_debug_assertions)]
150150
#[rustc_macro_transparency = "semitransparent"]
151151
pub macro debug_assert_nounwind {
152152
($cond:expr $(,)?) => {
153-
if $crate::cfg!(debug_assertions) {
153+
if $crate::intrinsics::debug_assertions() {
154154
if !$cond {
155155
$crate::panicking::panic_nounwind($crate::concat!("assertion failed: ", $crate::stringify!($cond)));
156156
}
157157
}
158158
},
159+
($cond:expr, $message:expr) => {
160+
if $crate::intrinsics::debug_assertions() {
161+
if !$cond {
162+
$crate::panicking::panic_nounwind($message);
163+
}
164+
}
165+
},
159166
($cond:expr, $($arg:tt)+) => {
160-
if $crate::cfg!(debug_assertions) {
167+
if $crate::intrinsics::debug_assertions() {
161168
if !$cond {
162169
$crate::panicking::panic_nounwind_fmt($crate::const_format_args!($($arg)+), false);
163170
}

library/core/src/ptr/alignment.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl Alignment {
7676
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
7777
#[inline]
7878
pub const unsafe fn new_unchecked(align: usize) -> Self {
79+
#[cfg(debug_assertions)]
7980
crate::panic::debug_assert_nounwind!(
8081
align.is_power_of_two(),
8182
"Alignment::new_unchecked requires a power of two"

library/core/src/slice/index.rs

+56-29
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Indexing implementations for `[T]`.
22
3+
use crate::intrinsics::assert_unsafe_precondition;
34
use crate::intrinsics::const_eval_select;
45
use crate::intrinsics::unchecked_sub;
56
use crate::ops;
6-
use crate::panic::debug_assert_nounwind;
77
use crate::ptr;
88

99
#[stable(feature = "rust1", since = "1.0.0")]
@@ -225,28 +225,36 @@ unsafe impl<T> SliceIndex<[T]> for usize {
225225

226226
#[inline]
227227
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
228-
debug_assert_nounwind!(
229-
self < slice.len(),
230-
"slice::get_unchecked requires that the index is within the slice",
231-
);
232228
// SAFETY: the caller guarantees that `slice` is not dangling, so it
233229
// cannot be longer than `isize::MAX`. They also guarantee that
234230
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
235231
// so the call to `add` is safe.
236232
unsafe {
237-
crate::hint::assert_unchecked(self < slice.len());
233+
assert_unsafe_precondition!(
234+
"slice::get_unchecked requires that the index is within the slice",
235+
(
236+
this: usize = self,
237+
len: usize = slice.len()
238+
) => this < len
239+
);
240+
crate::intrinsics::assume(self < slice.len());
238241
slice.as_ptr().add(self)
239242
}
240243
}
241244

242245
#[inline]
243246
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
244-
debug_assert_nounwind!(
245-
self < slice.len(),
246-
"slice::get_unchecked_mut requires that the index is within the slice",
247-
);
248247
// SAFETY: see comments for `get_unchecked` above.
249-
unsafe { slice.as_mut_ptr().add(self) }
248+
unsafe {
249+
assert_unsafe_precondition!(
250+
"slice::get_unchecked_mut requires that the index is within the slice",
251+
(
252+
this: usize = self,
253+
len: usize = slice.len()
254+
) => this < len
255+
);
256+
slice.as_mut_ptr().add(self)
257+
}
250258
}
251259

252260
#[inline]
@@ -290,25 +298,36 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
290298

291299
#[inline]
292300
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
293-
debug_assert_nounwind!(
294-
self.end() <= slice.len(),
295-
"slice::get_unchecked requires that the index is within the slice"
296-
);
297301
// SAFETY: the caller guarantees that `slice` is not dangling, so it
298302
// cannot be longer than `isize::MAX`. They also guarantee that
299303
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
300304
// so the call to `add` is safe.
301-
unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) }
305+
unsafe {
306+
assert_unsafe_precondition!(
307+
"slice::get_unchecked requires that the index is within the slice",
308+
(
309+
end: usize = self.end(),
310+
len: usize = slice.len()
311+
) => end <= len
312+
);
313+
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len())
314+
}
302315
}
303316

304317
#[inline]
305318
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
306-
debug_assert_nounwind!(
307-
self.end() <= slice.len(),
308-
"slice::get_unchecked_mut requires that the index is within the slice",
309-
);
310319
// SAFETY: see comments for `get_unchecked` above.
311-
unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) }
320+
unsafe {
321+
assert_unsafe_precondition!(
322+
"slice::get_unchecked_mut requires that the index is within the slice",
323+
(
324+
end: usize = self.end(),
325+
len: usize = slice.len()
326+
) => end <= len
327+
);
328+
329+
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len())
330+
}
312331
}
313332

314333
#[inline]
@@ -359,28 +378,36 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
359378

360379
#[inline]
361380
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
362-
debug_assert_nounwind!(
363-
self.end >= self.start && self.end <= slice.len(),
364-
"slice::get_unchecked requires that the range is within the slice",
365-
);
366381
// SAFETY: the caller guarantees that `slice` is not dangling, so it
367382
// cannot be longer than `isize::MAX`. They also guarantee that
368383
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
369384
// so the call to `add` is safe and the length calculation cannot overflow.
370385
unsafe {
386+
assert_unsafe_precondition!(
387+
"slice::get_unchecked requires that the range is within the slice",
388+
(
389+
end: usize = self.end,
390+
start: usize = self.start,
391+
len: usize = slice.len()
392+
) => end >= start && end <= len
393+
);
371394
let new_len = unchecked_sub(self.end, self.start);
372395
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
373396
}
374397
}
375398

376399
#[inline]
377400
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
378-
debug_assert_nounwind!(
379-
self.end >= self.start && self.end <= slice.len(),
380-
"slice::get_unchecked_mut requires that the range is within the slice",
381-
);
382401
// SAFETY: see comments for `get_unchecked` above.
383402
unsafe {
403+
assert_unsafe_precondition!(
404+
"slice::get_unchecked_mut requires that the range is within the slice",
405+
(
406+
end: usize = self.end,
407+
start: usize = self.start,
408+
len: usize = slice.len()
409+
) => end >= start && end <= len
410+
);
384411
let new_len = unchecked_sub(self.end, self.start);
385412
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
386413
}

tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir

+1-77
Original file line numberDiff line numberDiff line change
@@ -7,89 +7,13 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
77
scope 1 (inlined core::slice::<impl [u32]>::get_mut::<usize>) {
88
debug self => _1;
99
debug index => _2;
10-
scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) {
11-
debug self => _2;
12-
debug slice => _1;
13-
let mut _3: usize;
14-
let mut _4: bool;
15-
let mut _5: *mut [u32];
16-
let mut _7: *mut u32;
17-
let mut _8: &mut u32;
18-
scope 3 {
19-
scope 4 (inlined <usize as SliceIndex<[u32]>>::get_unchecked_mut) {
20-
debug self => _2;
21-
debug slice => _5;
22-
let mut _6: *mut u32;
23-
let mut _9: *mut [u32];
24-
let mut _10: &[&str];
25-
scope 5 {
26-
scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
27-
debug self => _5;
28-
}
29-
scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
30-
debug self => _6;
31-
debug count => _2;
32-
scope 12 {
33-
}
34-
}
35-
}
36-
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
37-
debug self => _9;
38-
let mut _11: *const [u32];
39-
scope 7 (inlined std::ptr::metadata::<[u32]>) {
40-
debug ptr => _11;
41-
scope 8 {
42-
}
43-
}
44-
}
45-
scope 9 (inlined Arguments::<'_>::new_const) {
46-
debug pieces => _10;
47-
}
48-
}
49-
}
50-
}
5110
}
5211

5312
bb0: {
54-
StorageLive(_7);
55-
StorageLive(_4);
56-
StorageLive(_3);
57-
_3 = Len((*_1));
58-
_4 = Lt(_2, move _3);
59-
switchInt(move _4) -> [0: bb1, otherwise: bb2];
13+
_0 = <usize as SliceIndex<[u32]>>::get_mut(move _2, move _1) -> [return: bb1, unwind unreachable];
6014
}
6115

6216
bb1: {
63-
StorageDead(_3);
64-
_0 = const Option::<&mut u32>::None;
65-
goto -> bb3;
66-
}
67-
68-
bb2: {
69-
StorageDead(_3);
70-
StorageLive(_8);
71-
StorageLive(_5);
72-
_5 = &raw mut (*_1);
73-
StorageLive(_9);
74-
StorageLive(_10);
75-
StorageLive(_11);
76-
StorageLive(_6);
77-
_6 = _5 as *mut u32 (PtrToPtr);
78-
_7 = Offset(_6, _2);
79-
StorageDead(_6);
80-
StorageDead(_11);
81-
StorageDead(_10);
82-
StorageDead(_9);
83-
StorageDead(_5);
84-
_8 = &mut (*_7);
85-
_0 = Option::<&mut u32>::Some(move _8);
86-
StorageDead(_8);
87-
goto -> bb3;
88-
}
89-
90-
bb3: {
91-
StorageDead(_4);
92-
StorageDead(_7);
9317
return;
9418
}
9519
}

tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir

+1-77
Original file line numberDiff line numberDiff line change
@@ -7,89 +7,13 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
77
scope 1 (inlined core::slice::<impl [u32]>::get_mut::<usize>) {
88
debug self => _1;
99
debug index => _2;
10-
scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) {
11-
debug self => _2;
12-
debug slice => _1;
13-
let mut _3: usize;
14-
let mut _4: bool;
15-
let mut _5: *mut [u32];
16-
let mut _7: *mut u32;
17-
let mut _8: &mut u32;
18-
scope 3 {
19-
scope 4 (inlined <usize as SliceIndex<[u32]>>::get_unchecked_mut) {
20-
debug self => _2;
21-
debug slice => _5;
22-
let mut _6: *mut u32;
23-
let mut _9: *mut [u32];
24-
let mut _10: &[&str];
25-
scope 5 {
26-
scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
27-
debug self => _5;
28-
}
29-
scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
30-
debug self => _6;
31-
debug count => _2;
32-
scope 12 {
33-
}
34-
}
35-
}
36-
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
37-
debug self => _9;
38-
let mut _11: *const [u32];
39-
scope 7 (inlined std::ptr::metadata::<[u32]>) {
40-
debug ptr => _11;
41-
scope 8 {
42-
}
43-
}
44-
}
45-
scope 9 (inlined Arguments::<'_>::new_const) {
46-
debug pieces => _10;
47-
}
48-
}
49-
}
50-
}
5110
}
5211

5312
bb0: {
54-
StorageLive(_7);
55-
StorageLive(_4);
56-
StorageLive(_3);
57-
_3 = Len((*_1));
58-
_4 = Lt(_2, move _3);
59-
switchInt(move _4) -> [0: bb1, otherwise: bb2];
13+
_0 = <usize as SliceIndex<[u32]>>::get_mut(move _2, move _1) -> [return: bb1, unwind continue];
6014
}
6115

6216
bb1: {
63-
StorageDead(_3);
64-
_0 = const Option::<&mut u32>::None;
65-
goto -> bb3;
66-
}
67-
68-
bb2: {
69-
StorageDead(_3);
70-
StorageLive(_8);
71-
StorageLive(_5);
72-
_5 = &raw mut (*_1);
73-
StorageLive(_9);
74-
StorageLive(_10);
75-
StorageLive(_11);
76-
StorageLive(_6);
77-
_6 = _5 as *mut u32 (PtrToPtr);
78-
_7 = Offset(_6, _2);
79-
StorageDead(_6);
80-
StorageDead(_11);
81-
StorageDead(_10);
82-
StorageDead(_9);
83-
StorageDead(_5);
84-
_8 = &mut (*_7);
85-
_0 = Option::<&mut u32>::Some(move _8);
86-
StorageDead(_8);
87-
goto -> bb3;
88-
}
89-
90-
bb3: {
91-
StorageDead(_4);
92-
StorageDead(_7);
9317
return;
9418
}
9519
}

0 commit comments

Comments
 (0)