Skip to content

Commit 17cacb7

Browse files
committed
Auto merge of #120762 - saethlin:assume-in-get-unchecked, r=<try>
Expand assumes to the other unchecked slice ops r? `@ghost`
2 parents 097cd98 + 1f4a2bc commit 17cacb7

6 files changed

+154
-67
lines changed

library/core/src/slice/index.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,10 @@ unsafe impl<T> SliceIndex<[T]> for usize {
265265
(this: usize = self, len: usize = slice.len()) => this < len
266266
);
267267
// SAFETY: see comments for `get_unchecked` above.
268-
unsafe { get_mut_noubcheck(slice, self) }
268+
unsafe {
269+
crate::intrinsics::assume(self < slice.len());
270+
get_mut_noubcheck(slice, self)
271+
}
269272
}
270273

271274
#[inline]
@@ -317,7 +320,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
317320
// cannot be longer than `isize::MAX`. They also guarantee that
318321
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
319322
// so the call to `add` is safe.
320-
unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) }
323+
unsafe {
324+
crate::intrinsics::assume(self.end() <= slice.len());
325+
get_offset_len_noubcheck(slice, self.start(), self.len())
326+
}
321327
}
322328

323329
#[inline]
@@ -329,7 +335,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
329335
);
330336

331337
// SAFETY: see comments for `get_unchecked` above.
332-
unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
338+
unsafe {
339+
crate::intrinsics::assume(self.end() <= slice.len());
340+
get_offset_len_mut_noubcheck(slice, self.start(), self.len())
341+
}
333342
}
334343

335344
#[inline]
@@ -404,6 +413,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
404413
unsafe {
405414
// Using the intrinsic avoids a superfluous UB check,
406415
// since the one on this method already checked `end >= start`.
416+
crate::intrinsics::assume(self.end <= slice.len());
407417
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
408418
get_offset_len_noubcheck(slice, self.start, new_len)
409419
}
@@ -422,6 +432,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
422432
);
423433
// SAFETY: see comments for `get_unchecked` above.
424434
unsafe {
435+
crate::intrinsics::assume(self.end <= slice.len());
425436
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
426437
get_offset_len_mut_noubcheck(slice, self.start, new_len)
427438
}

tests/codegen/issues/issue-116878.rs

+24
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

+31-18
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
88
let mut _4: usize;
99
scope 1 (inlined 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 <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 _10: *mut u32;
19-
scope 7 {
19+
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
20+
let _12: *mut u32;
21+
scope 9 {
2022
}
21-
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
22-
let _9: *mut u32;
23-
scope 9 {
23+
scope 10 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
24+
let _11: *mut u32;
25+
scope 11 {
2426
}
2527
}
2628
}
@@ -29,35 +31,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
2931
scope 5 (inlined std::ptr::metadata::<[u32]>) {
3032
}
3133
}
34+
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
35+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
36+
}
37+
}
3238
}
3339
}
3440

3541
bb0: {
3642
_3 = move (_2.0: usize);
3743
_4 = move (_2.1: usize);
38-
StorageLive(_11);
44+
StorageLive(_13);
3945
StorageLive(_5);
4046
_5 = &raw mut (*_1);
41-
StorageLive(_8);
47+
StorageLive(_10);
4248
StorageLive(_6);
4349
_6 = PtrMetadata(copy _1);
4450
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
4551
}
4652

4753
bb1: {
4854
StorageDead(_6);
49-
_8 = SubUnchecked(copy _4, copy _3);
50-
StorageLive(_10);
5155
StorageLive(_9);
52-
_9 = copy _5 as *mut u32 (PtrToPtr);
53-
_10 = Offset(copy _9, copy _3);
56+
StorageLive(_8);
57+
_8 = PtrMetadata(copy _1);
58+
_9 = Le(copy _4, move _8);
59+
StorageDead(_8);
60+
assume(move _9);
5461
StorageDead(_9);
55-
_11 = *mut [u32] from (copy _10, copy _8);
62+
_10 = SubUnchecked(copy _4, copy _3);
63+
StorageLive(_12);
64+
StorageLive(_11);
65+
_11 = copy _5 as *mut u32 (PtrToPtr);
66+
_12 = Offset(copy _11, copy _3);
67+
StorageDead(_11);
68+
_13 = *mut [u32] from (copy _12, copy _10);
69+
StorageDead(_12);
5670
StorageDead(_10);
57-
StorageDead(_8);
5871
StorageDead(_5);
59-
_0 = &mut (*_11);
60-
StorageDead(_11);
72+
_0 = &mut (*_13);
73+
StorageDead(_13);
6174
return;
6275
}
6376
}

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

+31-18
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
88
let mut _4: usize;
99
scope 1 (inlined 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 <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 _10: *mut u32;
19-
scope 7 {
19+
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
20+
let _12: *mut u32;
21+
scope 9 {
2022
}
21-
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
22-
let _9: *mut u32;
23-
scope 9 {
23+
scope 10 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
24+
let _11: *mut u32;
25+
scope 11 {
2426
}
2527
}
2628
}
@@ -29,35 +31,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
2931
scope 5 (inlined std::ptr::metadata::<[u32]>) {
3032
}
3133
}
34+
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
35+
scope 7 (inlined std::ptr::metadata::<[u32]>) {
36+
}
37+
}
3238
}
3339
}
3440

3541
bb0: {
3642
_3 = move (_2.0: usize);
3743
_4 = move (_2.1: usize);
38-
StorageLive(_11);
44+
StorageLive(_13);
3945
StorageLive(_5);
4046
_5 = &raw mut (*_1);
41-
StorageLive(_8);
47+
StorageLive(_10);
4248
StorageLive(_6);
4349
_6 = PtrMetadata(copy _1);
4450
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
4551
}
4652

4753
bb1: {
4854
StorageDead(_6);
49-
_8 = SubUnchecked(copy _4, copy _3);
50-
StorageLive(_10);
5155
StorageLive(_9);
52-
_9 = copy _5 as *mut u32 (PtrToPtr);
53-
_10 = Offset(copy _9, copy _3);
56+
StorageLive(_8);
57+
_8 = PtrMetadata(copy _1);
58+
_9 = Le(copy _4, move _8);
59+
StorageDead(_8);
60+
assume(move _9);
5461
StorageDead(_9);
55-
_11 = *mut [u32] from (copy _10, copy _8);
62+
_10 = SubUnchecked(copy _4, copy _3);
63+
StorageLive(_12);
64+
StorageLive(_11);
65+
_11 = copy _5 as *mut u32 (PtrToPtr);
66+
_12 = Offset(copy _11, copy _3);
67+
StorageDead(_11);
68+
_13 = *mut [u32] from (copy _12, copy _10);
69+
StorageDead(_12);
5670
StorageDead(_10);
57-
StorageDead(_8);
5871
StorageDead(_5);
59-
_0 = &mut (*_11);
60-
StorageDead(_11);
72+
_0 = &mut (*_13);
73+
StorageDead(_13);
6174
return;
6275
}
6376
}

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

+27-14
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
1010
scope 2 (inlined <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 _9: *const u32;
17-
scope 7 {
17+
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
18+
let _11: *const u32;
19+
scope 9 {
1820
}
19-
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
20-
let _8: *const u32;
21-
scope 9 {
21+
scope 10 (inlined core::slice::index::get_noubcheck::<u32>) {
22+
let _10: *const u32;
23+
scope 11 {
2224
}
2325
}
2426
}
@@ -27,29 +29,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
2729
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2830
}
2931
}
32+
scope 6 (inlined std::ptr::const_ptr::<impl *const [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(_7);
42+
StorageLive(_9);
3743
StorageLive(_5);
3844
_5 = PtrMetadata(copy _1);
3945
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
4046
}
4147

4248
bb1: {
4349
StorageDead(_5);
44-
_7 = SubUnchecked(copy _4, copy _3);
45-
StorageLive(_9);
4650
StorageLive(_8);
47-
_8 = copy _1 as *const u32 (PtrToPtr);
48-
_9 = Offset(copy _8, copy _3);
51+
StorageLive(_7);
52+
_7 = PtrMetadata(copy _1);
53+
_8 = Le(copy _4, move _7);
54+
StorageDead(_7);
55+
assume(move _8);
4956
StorageDead(_8);
50-
_0 = *const [u32] from (copy _9, copy _7);
57+
_9 = SubUnchecked(copy _4, copy _3);
58+
StorageLive(_11);
59+
StorageLive(_10);
60+
_10 = copy _1 as *const u32 (PtrToPtr);
61+
_11 = Offset(copy _10, copy _3);
62+
StorageDead(_10);
63+
_0 = *const [u32] from (copy _11, copy _9);
64+
StorageDead(_11);
5165
StorageDead(_9);
52-
StorageDead(_7);
5366
return;
5467
}
5568
}

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

+27-14
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
1010
scope 2 (inlined <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 _9: *const u32;
17-
scope 7 {
17+
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
18+
let _11: *const u32;
19+
scope 9 {
1820
}
19-
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
20-
let _8: *const u32;
21-
scope 9 {
21+
scope 10 (inlined core::slice::index::get_noubcheck::<u32>) {
22+
let _10: *const u32;
23+
scope 11 {
2224
}
2325
}
2426
}
@@ -27,29 +29,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
2729
scope 5 (inlined std::ptr::metadata::<[u32]>) {
2830
}
2931
}
32+
scope 6 (inlined std::ptr::const_ptr::<impl *const [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(_7);
42+
StorageLive(_9);
3743
StorageLive(_5);
3844
_5 = PtrMetadata(copy _1);
3945
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
4046
}
4147

4248
bb1: {
4349
StorageDead(_5);
44-
_7 = SubUnchecked(copy _4, copy _3);
45-
StorageLive(_9);
4650
StorageLive(_8);
47-
_8 = copy _1 as *const u32 (PtrToPtr);
48-
_9 = Offset(copy _8, copy _3);
51+
StorageLive(_7);
52+
_7 = PtrMetadata(copy _1);
53+
_8 = Le(copy _4, move _7);
54+
StorageDead(_7);
55+
assume(move _8);
4956
StorageDead(_8);
50-
_0 = *const [u32] from (copy _9, copy _7);
57+
_9 = SubUnchecked(copy _4, copy _3);
58+
StorageLive(_11);
59+
StorageLive(_10);
60+
_10 = copy _1 as *const u32 (PtrToPtr);
61+
_11 = Offset(copy _10, copy _3);
62+
StorageDead(_10);
63+
_0 = *const [u32] from (copy _11, copy _9);
64+
StorageDead(_11);
5165
StorageDead(_9);
52-
StorageDead(_7);
5366
return;
5467
}
5568
}

0 commit comments

Comments
 (0)