Skip to content

Commit d2ceee7

Browse files
Auto merge of #120762 - saethlin:assume-in-get-unchecked, r=<try>
Expand assumes to the other unchecked slice ops
2 parents 8392220 + 3cd517a commit d2ceee7

6 files changed

+154
-67
lines changed

library/core/src/slice/index.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
258258
(this: usize = self, len: usize = slice.len()) => this < len
259259
);
260260
// SAFETY: see comments for `get_unchecked` above.
261-
unsafe { slice_get_unchecked(slice, self) }
261+
unsafe {
262+
crate::intrinsics::assume(self < slice.len());
263+
slice_get_unchecked(slice, self)
264+
}
262265
}
263266

264267
#[inline]
@@ -312,7 +315,10 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
312315
// cannot be longer than `isize::MAX`. They also guarantee that
313316
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
314317
// so the call to `add` is safe.
315-
unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) }
318+
unsafe {
319+
crate::intrinsics::assume(self.end() <= slice.len());
320+
get_offset_len_noubcheck(slice, self.start(), self.len())
321+
}
316322
}
317323

318324
#[inline]
@@ -325,7 +331,10 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
325331
);
326332

327333
// SAFETY: see comments for `get_unchecked` above.
328-
unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
334+
unsafe {
335+
crate::intrinsics::assume(self.end() <= slice.len());
336+
get_offset_len_mut_noubcheck(slice, self.start(), self.len())
337+
}
329338
}
330339

331340
#[inline]
@@ -402,6 +411,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
402411
unsafe {
403412
// Using the intrinsic avoids a superfluous UB check,
404413
// since the one on this method already checked `end >= start`.
414+
crate::intrinsics::assume(self.end <= slice.len());
405415
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
406416
get_offset_len_noubcheck(slice, self.start, new_len)
407417
}
@@ -421,6 +431,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
421431
);
422432
// SAFETY: see comments for `get_unchecked` above.
423433
unsafe {
434+
crate::intrinsics::assume(self.end <= slice.len());
424435
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
425436
get_offset_len_mut_noubcheck(slice, self.start, new_len)
426437
}

tests/codegen-llvm/issues/issue-116878.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,27 @@ pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 {
99
// CHECK-NOT: panic_bounds_check
1010
a + s[0]
1111
}
12+
13+
// CHECK-LABEL: @unchecked_slice_no_bounds_check_mut
14+
#[no_mangle]
15+
pub unsafe fn unchecked_slice_no_bounds_check_mut(s: &mut [u8]) -> u8 {
16+
let a = *s.get_unchecked_mut(2);
17+
// CHECK-NOT: panic_bounds_check
18+
a + s[1]
19+
}
20+
21+
// CHECK-LABEL: @unchecked_slice_no_bounds_check_range
22+
#[no_mangle]
23+
pub unsafe fn unchecked_slice_no_bounds_check_range(s: &[u8]) -> u8 {
24+
let _a = &s.get_unchecked(..1);
25+
// CHECK-NOT: panic_bounds_check
26+
s[0]
27+
}
28+
29+
// CHECK-LABEL: @unchecked_slice_no_bounds_check_range_mut
30+
#[no_mangle]
31+
pub unsafe fn unchecked_slice_no_bounds_check_range_mut(s: &mut [u8]) -> u8 {
32+
let _a = &mut s.get_unchecked_mut(..2);
33+
// CHECK-NOT: panic_bounds_check
34+
s[1]
35+
}

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

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
88
let mut _4: usize;
99
scope 1 (inlined #[track_caller] core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
1010
let mut _5: *mut [u32];
11-
let mut _11: *mut [u32];
11+
let mut _13: *mut [u32];
1212
scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
1313
let mut _6: usize;
1414
let _7: ();
15-
let _8: usize;
15+
let mut _8: usize;
16+
let mut _9: bool;
17+
let _10: usize;
1618
scope 3 {
17-
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
18-
let _9: *mut u32;
19-
scope 7 {
20-
let _10: *mut u32;
21-
scope 8 {
19+
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
20+
let _11: *mut u32;
21+
scope 9 {
22+
let _12: *mut u32;
23+
scope 10 {
2224
}
2325
}
2426
}
@@ -27,35 +29,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
2729
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2830
}
2931
}
32+
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
33+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
34+
}
35+
}
3036
}
3137
}
3238

3339
bb0: {
3440
_3 = move (_2.0: usize);
3541
_4 = move (_2.1: usize);
36-
StorageLive(_11);
42+
StorageLive(_13);
3743
StorageLive(_5);
3844
_5 = &raw mut (*_1);
39-
StorageLive(_8);
45+
StorageLive(_10);
4046
StorageLive(_6);
4147
_6 = PtrMetadata(copy _1);
4248
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
4349
}
4450

4551
bb1: {
4652
StorageDead(_6);
47-
_8 = SubUnchecked(copy _4, copy _3);
4853
StorageLive(_9);
49-
StorageLive(_10);
50-
_9 = copy _5 as *mut u32 (PtrToPtr);
51-
_10 = Offset(copy _9, copy _3);
52-
_11 = *mut [u32] from (copy _10, copy _8);
53-
StorageDead(_10);
54-
StorageDead(_9);
54+
StorageLive(_8);
55+
_8 = PtrMetadata(copy _1);
56+
_9 = Le(copy _4, move _8);
5557
StorageDead(_8);
56-
StorageDead(_5);
57-
_0 = &mut (*_11);
58+
assume(move _9);
59+
StorageDead(_9);
60+
_10 = SubUnchecked(copy _4, copy _3);
61+
StorageLive(_11);
62+
StorageLive(_12);
63+
_11 = copy _5 as *mut u32 (PtrToPtr);
64+
_12 = Offset(copy _11, copy _3);
65+
_13 = *mut [u32] from (copy _12, copy _10);
66+
StorageDead(_12);
5867
StorageDead(_11);
68+
StorageDead(_10);
69+
StorageDead(_5);
70+
_0 = &mut (*_13);
71+
StorageDead(_13);
5972
return;
6073
}
6174
}

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

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
88
let mut _4: usize;
99
scope 1 (inlined #[track_caller] core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
1010
let mut _5: *mut [u32];
11-
let mut _11: *mut [u32];
11+
let mut _13: *mut [u32];
1212
scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
1313
let mut _6: usize;
1414
let _7: ();
15-
let _8: usize;
15+
let mut _8: usize;
16+
let mut _9: bool;
17+
let _10: usize;
1618
scope 3 {
17-
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
18-
let _9: *mut u32;
19-
scope 7 {
20-
let _10: *mut u32;
21-
scope 8 {
19+
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
20+
let _11: *mut u32;
21+
scope 9 {
22+
let _12: *mut u32;
23+
scope 10 {
2224
}
2325
}
2426
}
@@ -27,35 +29,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
2729
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2830
}
2931
}
32+
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
33+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
34+
}
35+
}
3036
}
3137
}
3238

3339
bb0: {
3440
_3 = move (_2.0: usize);
3541
_4 = move (_2.1: usize);
36-
StorageLive(_11);
42+
StorageLive(_13);
3743
StorageLive(_5);
3844
_5 = &raw mut (*_1);
39-
StorageLive(_8);
45+
StorageLive(_10);
4046
StorageLive(_6);
4147
_6 = PtrMetadata(copy _1);
4248
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
4349
}
4450

4551
bb1: {
4652
StorageDead(_6);
47-
_8 = SubUnchecked(copy _4, copy _3);
4853
StorageLive(_9);
49-
StorageLive(_10);
50-
_9 = copy _5 as *mut u32 (PtrToPtr);
51-
_10 = Offset(copy _9, copy _3);
52-
_11 = *mut [u32] from (copy _10, copy _8);
53-
StorageDead(_10);
54-
StorageDead(_9);
54+
StorageLive(_8);
55+
_8 = PtrMetadata(copy _1);
56+
_9 = Le(copy _4, move _8);
5557
StorageDead(_8);
56-
StorageDead(_5);
57-
_0 = &mut (*_11);
58+
assume(move _9);
59+
StorageDead(_9);
60+
_10 = SubUnchecked(copy _4, copy _3);
61+
StorageLive(_11);
62+
StorageLive(_12);
63+
_11 = copy _5 as *mut u32 (PtrToPtr);
64+
_12 = Offset(copy _11, copy _3);
65+
_13 = *mut [u32] from (copy _12, copy _10);
66+
StorageDead(_12);
5867
StorageDead(_11);
68+
StorageDead(_10);
69+
StorageDead(_5);
70+
_0 = &mut (*_13);
71+
StorageDead(_13);
5972
return;
6073
}
6174
}

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

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
1010
scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
1111
let mut _5: usize;
1212
let _6: ();
13-
let _7: usize;
13+
let mut _7: usize;
14+
let mut _8: bool;
15+
let _9: usize;
1416
scope 3 {
15-
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
16-
let _8: *const u32;
17-
scope 7 {
18-
let _9: *const u32;
19-
scope 8 {
17+
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
18+
let _10: *const u32;
19+
scope 9 {
20+
let _11: *const u32;
21+
scope 10 {
2022
}
2123
}
2224
}
@@ -25,29 +27,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
2527
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2628
}
2729
}
30+
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
31+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
32+
}
33+
}
2834
}
2935
}
3036

3137
bb0: {
3238
_3 = move (_2.0: usize);
3339
_4 = move (_2.1: usize);
34-
StorageLive(_7);
40+
StorageLive(_9);
3541
StorageLive(_5);
3642
_5 = PtrMetadata(copy _1);
3743
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
3844
}
3945

4046
bb1: {
4147
StorageDead(_5);
42-
_7 = SubUnchecked(copy _4, copy _3);
4348
StorageLive(_8);
44-
StorageLive(_9);
45-
_8 = copy _1 as *const u32 (PtrToPtr);
46-
_9 = Offset(copy _8, copy _3);
47-
_0 = *const [u32] from (copy _9, copy _7);
48-
StorageDead(_9);
49-
StorageDead(_8);
49+
StorageLive(_7);
50+
_7 = PtrMetadata(copy _1);
51+
_8 = Le(copy _4, move _7);
5052
StorageDead(_7);
53+
assume(move _8);
54+
StorageDead(_8);
55+
_9 = SubUnchecked(copy _4, copy _3);
56+
StorageLive(_10);
57+
StorageLive(_11);
58+
_10 = copy _1 as *const u32 (PtrToPtr);
59+
_11 = Offset(copy _10, copy _3);
60+
_0 = *const [u32] from (copy _11, copy _9);
61+
StorageDead(_11);
62+
StorageDead(_10);
63+
StorageDead(_9);
5164
return;
5265
}
5366
}

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

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
1010
scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
1111
let mut _5: usize;
1212
let _6: ();
13-
let _7: usize;
13+
let mut _7: usize;
14+
let mut _8: bool;
15+
let _9: usize;
1416
scope 3 {
15-
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
16-
let _8: *const u32;
17-
scope 7 {
18-
let _9: *const u32;
19-
scope 8 {
17+
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
18+
let _10: *const u32;
19+
scope 9 {
20+
let _11: *const u32;
21+
scope 10 {
2022
}
2123
}
2224
}
@@ -25,29 +27,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
2527
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2628
}
2729
}
30+
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
31+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
32+
}
33+
}
2834
}
2935
}
3036

3137
bb0: {
3238
_3 = move (_2.0: usize);
3339
_4 = move (_2.1: usize);
34-
StorageLive(_7);
40+
StorageLive(_9);
3541
StorageLive(_5);
3642
_5 = PtrMetadata(copy _1);
3743
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
3844
}
3945

4046
bb1: {
4147
StorageDead(_5);
42-
_7 = SubUnchecked(copy _4, copy _3);
4348
StorageLive(_8);
44-
StorageLive(_9);
45-
_8 = copy _1 as *const u32 (PtrToPtr);
46-
_9 = Offset(copy _8, copy _3);
47-
_0 = *const [u32] from (copy _9, copy _7);
48-
StorageDead(_9);
49-
StorageDead(_8);
49+
StorageLive(_7);
50+
_7 = PtrMetadata(copy _1);
51+
_8 = Le(copy _4, move _7);
5052
StorageDead(_7);
53+
assume(move _8);
54+
StorageDead(_8);
55+
_9 = SubUnchecked(copy _4, copy _3);
56+
StorageLive(_10);
57+
StorageLive(_11);
58+
_10 = copy _1 as *const u32 (PtrToPtr);
59+
_11 = Offset(copy _10, copy _3);
60+
_0 = *const [u32] from (copy _11, copy _9);
61+
StorageDead(_11);
62+
StorageDead(_10);
63+
StorageDead(_9);
5164
return;
5265
}
5366
}

0 commit comments

Comments
 (0)