mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #108763 - scottmcm:indexing-nuw-lengths, r=cuviper
Use `nuw` when calculating slice lengths from `Range`s An `assume` would definitely not be worth it, but since the flag is almost free we might as well tell LLVM this, especially on `_unchecked` calls where there's no obvious way for it to deduce it. (Today neither safe nor unsafe indexing gets it: <https://rust.godbolt.org/z/G1jYT548s>)
This commit is contained in:
commit
160c2ebeca
@ -2,6 +2,7 @@
|
||||
|
||||
use crate::intrinsics::assert_unsafe_precondition;
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::intrinsics::unchecked_sub;
|
||||
use crate::ops;
|
||||
use crate::ptr;
|
||||
|
||||
@ -375,14 +376,15 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
|
||||
// SAFETY: the caller guarantees that `slice` is not dangling, so it
|
||||
// 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.
|
||||
// so the call to `add` is safe and the length calculation cannot overflow.
|
||||
unsafe {
|
||||
assert_unsafe_precondition!(
|
||||
"slice::get_unchecked requires that the range is within the slice",
|
||||
[T](this: ops::Range<usize>, slice: *const [T]) =>
|
||||
this.end >= this.start && this.end <= slice.len()
|
||||
);
|
||||
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
|
||||
let new_len = unchecked_sub(self.end, self.start);
|
||||
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,7 +398,8 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
|
||||
[T](this: ops::Range<usize>, slice: *mut [T]) =>
|
||||
this.end >= this.start && this.end <= slice.len()
|
||||
);
|
||||
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
|
||||
let new_len = unchecked_sub(self.end, self.start);
|
||||
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
|
||||
}
|
||||
}
|
||||
|
||||
|
35
tests/codegen/slice-indexing.rs
Normal file
35
tests/codegen/slice-indexing.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// compile-flags: -O
|
||||
// only-64bit (because the LLVM type of i64 for usize shows up)
|
||||
// ignore-debug: the debug assertions get in the way
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
// CHECK-LABEL: @index_by_range(
|
||||
#[no_mangle]
|
||||
pub fn index_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
|
||||
// CHECK: sub nuw i64
|
||||
&x[r]
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @get_unchecked_by_range(
|
||||
#[no_mangle]
|
||||
pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
|
||||
// CHECK: sub nuw i64
|
||||
x.get_unchecked(r)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @index_mut_by_range(
|
||||
#[no_mangle]
|
||||
pub fn index_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
|
||||
// CHECK: sub nuw i64
|
||||
&mut x[r]
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @get_unchecked_mut_by_range(
|
||||
#[no_mangle]
|
||||
pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
|
||||
// CHECK: sub nuw i64
|
||||
x.get_unchecked_mut(r)
|
||||
}
|
9
tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
Normal file
9
tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![feature(const_slice_index)]
|
||||
|
||||
const A: [(); 5] = [(), (), (), (), ()];
|
||||
|
||||
// Since the indexing is on a ZST, the addresses are all fine,
|
||||
// but we should still catch the bad range.
|
||||
const B: &[()] = unsafe { A.get_unchecked(3..1) };
|
||||
|
||||
fn main() {}
|
18
tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
Normal file
18
tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $SRC_DIR/core/src/slice/index.rs:LL:COL
|
||||
|
|
||||
= note: overflow executing `unchecked_sub`
|
||||
|
|
||||
note: inside `<std::ops::Range<usize> as SliceIndex<[()]>>::get_unchecked`
|
||||
--> $SRC_DIR/core/src/slice/index.rs:LL:COL
|
||||
note: inside `core::slice::<impl [()]>::get_unchecked::<std::ops::Range<usize>>`
|
||||
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
|
||||
note: inside `B`
|
||||
--> $DIR/ub-slice-get-unchecked.rs:7:27
|
||||
|
|
||||
LL | const B: &[()] = unsafe { A.get_unchecked(3..1) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
Loading…
Reference in New Issue
Block a user