Someone will correct me if I’m wrong, but since indexing past a slice is undefined, I don’t think anyone would object to making it fail sooner & safer in debug mode.
That said, as an example of incorrect code that works:
let slice1 = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
let slice2 = &slice1[..5];
assert_eq!(slice2.get_unchecked(9), 9);
This can be “made correct” by casting the slice to the proper length that you know is actually there. This is actually somewhat common in parsing applications: you keep a slice of what this node covers but also an offset to the start of the buffer such that you can look at everything before to find the line/column late instead of eagerly. Since that’s going backwards instead of forwards, though, 100% of them correctly create the slice instead of just indexing past one they already have.
Another wrinkle is that debug_assert! in the stdlib basically never runs, as the stdlib is always compiled in optimized mode. This would have to hook into the existing (somewhat hacky workaround) plumbing that enables overflow checks in debug everywhere (or something similar).
However, this could be done exclusively in a crate if you’re ok using different method names: (pseudo-rust for simplicity)
impl DebugAssertSlicing for &[T] {
fn get_debug_checked(&self, idx: usize) -> Self::Item {
if cfg!(debug_assertions) {
self[idx]
} else {
self.get_unchecked(idx)
}
}
// and so on
}