diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index aafa19c0dd3d3..96222cd8e6733 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -265,7 +265,10 @@ unsafe impl 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 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 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 SliceIndex<[T]> for ops::Range { 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 SliceIndex<[T]> for ops::Range { ); // 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) } diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs index daf46c8bb554a..764903c879822 100644 --- a/tests/codegen/issues/issue-116878.rs +++ b/tests/codegen/issues/issue-116878.rs @@ -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] +} diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 220e881f86645..d6c3188ff6b65 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; - let mut _11: *mut [u32]; + let mut _13: *mut [u32]; scope 2 (inlined 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::) { - let _10: *mut u32; - scope 7 { + scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _12: *mut u32; + scope 9 { } - scope 8 (inlined core::slice::index::get_mut_noubcheck::) { - let _9: *mut u32; - scope 9 { + scope 10 (inlined core::slice::index::get_mut_noubcheck::) { + let _11: *mut u32; + scope 11 { } } } @@ -29,16 +31,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::mut_ptr::::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 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable]; @@ -46,18 +52,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> 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; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 220e881f86645..d6c3188ff6b65 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,19 +8,21 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; - let mut _11: *mut [u32]; + let mut _13: *mut [u32]; scope 2 (inlined 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::) { - let _10: *mut u32; - scope 7 { + scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _12: *mut u32; + scope 9 { } - scope 8 (inlined core::slice::index::get_mut_noubcheck::) { - let _9: *mut u32; - scope 9 { + scope 10 (inlined core::slice::index::get_mut_noubcheck::) { + let _11: *mut u32; + scope 11 { } } } @@ -29,16 +31,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::mut_ptr::::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 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable]; @@ -46,18 +52,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> 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; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 1e0df94b67fb1..3adcdc2a0cafd 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 2 (inlined 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::) { - let _9: *const u32; - scope 7 { + scope 8 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _11: *const u32; + scope 9 { } - scope 8 (inlined core::slice::index::get_noubcheck::) { - let _8: *const u32; - scope 9 { + scope 10 (inlined core::slice::index::get_noubcheck::) { + let _10: *const u32; + scope 11 { } } } @@ -27,13 +29,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::const_ptr::::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 = as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable]; @@ -41,15 +47,22 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - 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; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 1e0df94b67fb1..3adcdc2a0cafd 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -10,15 +10,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 2 (inlined 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::) { - let _9: *const u32; - scope 7 { + scope 8 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _11: *const u32; + scope 9 { } - scope 8 (inlined core::slice::index::get_noubcheck::) { - let _8: *const u32; - scope 9 { + scope 10 (inlined core::slice::index::get_noubcheck::) { + let _10: *const u32; + scope 11 { } } } @@ -27,13 +29,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::const_ptr::::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 = as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable]; @@ -41,15 +47,22 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - 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; } }