Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand assumes to the other unchecked slice ops #120762

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions library/core/src/slice/index.rs
Original file line number Diff line number Diff line change
@@ -265,7 +265,10 @@ unsafe impl<T> SliceIndex<[T]> for usize {
(this: usize = self, len: usize = slice.len()) => this < len
);
// SAFETY: see comments for `get_unchecked` above.
unsafe { get_mut_noubcheck(slice, self) }
unsafe {
crate::intrinsics::assume(self < slice.len());
get_mut_noubcheck(slice, self)
}
}

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

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

// SAFETY: see comments for `get_unchecked` above.
unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
unsafe {
crate::intrinsics::assume(self.end() <= slice.len());
get_offset_len_mut_noubcheck(slice, self.start(), self.len())
}
}

#[inline]
@@ -404,6 +413,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
unsafe {
// Using the intrinsic avoids a superfluous UB check,
// since the one on this method already checked `end >= start`.
crate::intrinsics::assume(self.end <= slice.len());
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
get_offset_len_noubcheck(slice, self.start, new_len)
}
@@ -422,6 +432,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
);
// SAFETY: see comments for `get_unchecked` above.
unsafe {
crate::intrinsics::assume(self.end <= slice.len());
let new_len = crate::intrinsics::unchecked_sub(self.end, self.start);
get_offset_len_mut_noubcheck(slice, self.start, new_len)
}
24 changes: 24 additions & 0 deletions tests/codegen/issues/issue-116878.rs
Original file line number Diff line number Diff line change
@@ -9,3 +9,27 @@ pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 {
// CHECK-NOT: panic_bounds_check
a + s[0]
}

// CHECK-LABEL: @unchecked_slice_no_bounds_check_mut
#[no_mangle]
pub unsafe fn unchecked_slice_no_bounds_check_mut(s: &mut [u8]) -> u8 {
let a = *s.get_unchecked_mut(2);
// CHECK-NOT: panic_bounds_check
a + s[1]
}

// CHECK-LABEL: @unchecked_slice_no_bounds_check_range
#[no_mangle]
pub unsafe fn unchecked_slice_no_bounds_check_range(s: &[u8]) -> u8 {
let _a = &s.get_unchecked(..1);
// CHECK-NOT: panic_bounds_check
s[0]
}

// CHECK-LABEL: @unchecked_slice_no_bounds_check_range_mut
#[no_mangle]
pub unsafe fn unchecked_slice_no_bounds_check_range_mut(s: &mut [u8]) -> u8 {
let _a = &mut s.get_unchecked_mut(..2);
// CHECK-NOT: panic_bounds_check
s[1]
}
Original file line number Diff line number Diff line change
@@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
let mut _4: usize;
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
let mut _5: *mut [u32];
let mut _11: *mut [u32];
let mut _13: *mut [u32];
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
let mut _6: usize;
let _7: ();
let _8: usize;
let mut _8: usize;
let mut _9: bool;
let _10: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _10: *mut u32;
scope 7 {
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _12: *mut u32;
scope 9 {
}
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _9: *mut u32;
scope 9 {
scope 10 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _11: *mut u32;
scope 11 {
}
}
}
@@ -29,35 +31,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
scope 7 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
}

bb0: {
_3 = move (_2.0: usize);
_4 = move (_2.1: usize);
StorageLive(_11);
StorageLive(_13);
StorageLive(_5);
_5 = &raw mut (*_1);
StorageLive(_8);
StorageLive(_10);
StorageLive(_6);
_6 = PtrMetadata(copy _1);
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_6);
_8 = SubUnchecked(copy _4, copy _3);
StorageLive(_10);
StorageLive(_9);
_9 = copy _5 as *mut u32 (PtrToPtr);
_10 = Offset(copy _9, copy _3);
StorageLive(_8);
_8 = PtrMetadata(copy _1);
_9 = Le(copy _4, move _8);
StorageDead(_8);
assume(move _9);
StorageDead(_9);
_11 = *mut [u32] from (copy _10, copy _8);
_10 = SubUnchecked(copy _4, copy _3);
StorageLive(_12);
StorageLive(_11);
_11 = copy _5 as *mut u32 (PtrToPtr);
_12 = Offset(copy _11, copy _3);
StorageDead(_11);
_13 = *mut [u32] from (copy _12, copy _10);
StorageDead(_12);
StorageDead(_10);
StorageDead(_8);
StorageDead(_5);
_0 = &mut (*_11);
StorageDead(_11);
_0 = &mut (*_13);
StorageDead(_13);
return;
}
}
Original file line number Diff line number Diff line change
@@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
let mut _4: usize;
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
let mut _5: *mut [u32];
let mut _11: *mut [u32];
let mut _13: *mut [u32];
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
let mut _6: usize;
let _7: ();
let _8: usize;
let mut _8: usize;
let mut _9: bool;
let _10: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _10: *mut u32;
scope 7 {
scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _12: *mut u32;
scope 9 {
}
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _9: *mut u32;
scope 9 {
scope 10 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _11: *mut u32;
scope 11 {
}
}
}
@@ -29,35 +31,46 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
scope 7 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
}

bb0: {
_3 = move (_2.0: usize);
_4 = move (_2.1: usize);
StorageLive(_11);
StorageLive(_13);
StorageLive(_5);
_5 = &raw mut (*_1);
StorageLive(_8);
StorageLive(_10);
StorageLive(_6);
_6 = PtrMetadata(copy _1);
_7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_6);
_8 = SubUnchecked(copy _4, copy _3);
StorageLive(_10);
StorageLive(_9);
_9 = copy _5 as *mut u32 (PtrToPtr);
_10 = Offset(copy _9, copy _3);
StorageLive(_8);
_8 = PtrMetadata(copy _1);
_9 = Le(copy _4, move _8);
StorageDead(_8);
assume(move _9);
StorageDead(_9);
_11 = *mut [u32] from (copy _10, copy _8);
_10 = SubUnchecked(copy _4, copy _3);
StorageLive(_12);
StorageLive(_11);
_11 = copy _5 as *mut u32 (PtrToPtr);
_12 = Offset(copy _11, copy _3);
StorageDead(_11);
_13 = *mut [u32] from (copy _12, copy _10);
StorageDead(_12);
StorageDead(_10);
StorageDead(_8);
StorageDead(_5);
_0 = &mut (*_11);
StorageDead(_11);
_0 = &mut (*_13);
StorageDead(_13);
return;
}
}
Original file line number Diff line number Diff line change
@@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
let mut _5: usize;
let _6: ();
let _7: usize;
let mut _7: usize;
let mut _8: bool;
let _9: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _9: *const u32;
scope 7 {
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _11: *const u32;
scope 9 {
}
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
let _8: *const u32;
scope 9 {
scope 10 (inlined core::slice::index::get_noubcheck::<u32>) {
let _10: *const u32;
scope 11 {
}
}
}
@@ -27,29 +29,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
scope 7 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
}

bb0: {
_3 = move (_2.0: usize);
_4 = move (_2.1: usize);
StorageLive(_7);
StorageLive(_9);
StorageLive(_5);
_5 = PtrMetadata(copy _1);
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_5);
_7 = SubUnchecked(copy _4, copy _3);
StorageLive(_9);
StorageLive(_8);
_8 = copy _1 as *const u32 (PtrToPtr);
_9 = Offset(copy _8, copy _3);
StorageLive(_7);
_7 = PtrMetadata(copy _1);
_8 = Le(copy _4, move _7);
StorageDead(_7);
assume(move _8);
StorageDead(_8);
_0 = *const [u32] from (copy _9, copy _7);
_9 = SubUnchecked(copy _4, copy _3);
StorageLive(_11);
StorageLive(_10);
_10 = copy _1 as *const u32 (PtrToPtr);
_11 = Offset(copy _10, copy _3);
StorageDead(_10);
_0 = *const [u32] from (copy _11, copy _9);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
return;
}
}
Original file line number Diff line number Diff line change
@@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
let mut _5: usize;
let _6: ();
let _7: usize;
let mut _7: usize;
let mut _8: bool;
let _9: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _9: *const u32;
scope 7 {
scope 8 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _11: *const u32;
scope 9 {
}
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
let _8: *const u32;
scope 9 {
scope 10 (inlined core::slice::index::get_noubcheck::<u32>) {
let _10: *const u32;
scope 11 {
}
}
}
@@ -27,29 +29,40 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
scope 7 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
}

bb0: {
_3 = move (_2.0: usize);
_4 = move (_2.1: usize);
StorageLive(_7);
StorageLive(_9);
StorageLive(_5);
_5 = PtrMetadata(copy _1);
_6 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_5);
_7 = SubUnchecked(copy _4, copy _3);
StorageLive(_9);
StorageLive(_8);
_8 = copy _1 as *const u32 (PtrToPtr);
_9 = Offset(copy _8, copy _3);
StorageLive(_7);
_7 = PtrMetadata(copy _1);
_8 = Le(copy _4, move _7);
StorageDead(_7);
assume(move _8);
StorageDead(_8);
_0 = *const [u32] from (copy _9, copy _7);
_9 = SubUnchecked(copy _4, copy _3);
StorageLive(_11);
StorageLive(_10);
_10 = copy _1 as *const u32 (PtrToPtr);
_11 = Offset(copy _10, copy _3);
StorageDead(_10);
_0 = *const [u32] from (copy _11, copy _9);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
return;
}
}
Loading