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:
parent
7820b62d20
commit
3554036280
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::intrinsics::assert_unsafe_precondition;
|
use crate::intrinsics::assert_unsafe_precondition;
|
||||||
use crate::intrinsics::const_eval_select;
|
use crate::intrinsics::const_eval_select;
|
||||||
|
use crate::intrinsics::unchecked_sub;
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::ptr;
|
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
|
// SAFETY: the caller guarantees that `slice` is not dangling, so it
|
||||||
// cannot be longer than `isize::MAX`. They also guarantee that
|
// cannot be longer than `isize::MAX`. They also guarantee that
|
||||||
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
|
// `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 {
|
unsafe {
|
||||||
assert_unsafe_precondition!(
|
assert_unsafe_precondition!(
|
||||||
"slice::get_unchecked requires that the range is within the slice",
|
"slice::get_unchecked requires that the range is within the slice",
|
||||||
[T](this: ops::Range<usize>, slice: *const [T]) =>
|
[T](this: ops::Range<usize>, slice: *const [T]) =>
|
||||||
this.end >= this.start && this.end <= slice.len()
|
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]) =>
|
[T](this: ops::Range<usize>, slice: *mut [T]) =>
|
||||||
this.end >= this.start && this.end <= slice.len()
|
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…
x
Reference in New Issue
Block a user