From 39745288dba7b2e1d88a782b1ad5266e2eaedc61 Mon Sep 17 00:00:00 2001 From: Bardi Harborow Date: Sat, 5 Sep 2026 07:33:30 +0000 Subject: [PATCH] Report precondition violation for `::get_unchecked` in const-eval * Add a test for the diagnostics on `::get_unchecked` in const-eval * Report a precondition violation for `::get_unchecked` in const-eval The precondition check was gated on `check_language_ub`, which is disabled in const-eval and Miri, on the grounds that the `assume` below it is language UB that the interpreter will catch anyway. It does catch it, but only as "`assume` called with `false`", which says nothing about what the caller did wrong. This commit instead gates the check on `check_library_ub`, matching `get_unchecked_mut`, so that the interpreter reports the violated precondition. * fixup! Report a precondition violation for `::get_unchecked` in const-eval * tweak comment Co-authored-by: Ralf Jung --- library/core/src/slice/index.rs | 2 +- .../const-eval/ub-slice-get-unchecked.rs | 18 +++++++++-- .../const-eval/ub-slice-get-unchecked.stderr | 32 ++++++++++++++++--- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index b82d79232becc..47f934c37cab4 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -204,7 +204,7 @@ const unsafe impl SliceIndex<[T]> for usize { #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { assert_unsafe_precondition!( - check_language_ub, // okay because of the `assume` below + check_library_ub, // Hitting the `assume` provides worse const-eval and Miri diagnostics. "slice::get_unchecked requires that the index is within the slice", (this: usize = self, len: usize = slice.len()) => this < len ); diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index ad2b49e60498d..3196d7809f364 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,10 +1,24 @@ #![feature(const_index, const_trait_impl)] -const A: [(); 5] = [(), (), (), (), ()]; +const ZST_ARRAY: [(); 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) }; +const ZST_RANGE_OOB: &[()] = unsafe { ZST_ARRAY.get_unchecked(3..1) }; //~^ ERROR: slice::get_unchecked requires that the range is within the slice +const ZST_INDEX_OOB: &() = unsafe { ZST_ARRAY.get_unchecked(9) }; +//~^ ERROR: slice::get_unchecked requires that the index is within the slice + +const ARRAY: [i32; 5] = [1, 2, 3, 4, 5]; + +const INDEX_OOB: &i32 = unsafe { ARRAY.get_unchecked(9) }; +//~^ ERROR: slice::get_unchecked requires that the index is within the slice + +const INDEX_OOB_MUT: () = unsafe { + let mut array = ARRAY; + let _ = array.get_unchecked_mut(9); + //~^ ERROR: slice::get_unchecked_mut requires that the index is within the slice +}; + fn main() {} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index 88ea310f19c68..052ddb527a546 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,11 +1,35 @@ error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. - --> $DIR/ub-slice-get-unchecked.rs:7:27 + --> $DIR/ub-slice-get-unchecked.rs:7:39 | -LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here +LL | const ZST_RANGE_OOB: &[()] = unsafe { ZST_ARRAY.get_unchecked(3..1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST_RANGE_OOB` failed here -error: aborting due to 1 previous error +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the index is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:10:37 + | +LL | const ZST_INDEX_OOB: &() = unsafe { ZST_ARRAY.get_unchecked(9) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST_INDEX_OOB` failed here + +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the index is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:15:34 + | +LL | const INDEX_OOB: &i32 = unsafe { ARRAY.get_unchecked(9) }; + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INDEX_OOB` failed here + +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked_mut requires that the index is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:20:13 + | +LL | let _ = array.get_unchecked_mut(9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INDEX_OOB_MUT` failed here + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`.