Skip to content

Commit 6473bd2

Browse files
committed
Consolidate panicking functions in slice/index.rs
Consolidate all the panicking functions in `slice/index.rs` to use a single `slice_index_fail` function, similar to how it is done in `str/traits.rs`.
1 parent 29cdc6a commit 6473bd2

File tree

5 files changed

+161
-69
lines changed

5 files changed

+161
-69
lines changed

library/core/src/slice/index.rs

Lines changed: 88 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,41 @@ where
3434
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
3535
#[cfg_attr(feature = "panic_immediate_abort", inline)]
3636
#[track_caller]
37-
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
38-
const_panic!(
39-
"slice start index is out of range for slice",
40-
"range start index {index} out of range for slice of length {len}",
41-
index: usize,
42-
len: usize,
43-
)
44-
}
37+
const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! {
38+
if start > len {
39+
const_panic!(
40+
"slice start index is out of range for slice",
41+
"range start index {start} out of range for slice of length {len}",
42+
start: usize,
43+
len: usize,
44+
)
45+
}
4546

46-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
47-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
48-
#[track_caller]
49-
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
50-
const_panic!(
51-
"slice end index is out of range for slice",
52-
"range end index {index} out of range for slice of length {len}",
53-
index: usize,
54-
len: usize,
55-
)
56-
}
47+
if end > len {
48+
const_panic!(
49+
"slice end index is out of range for slice",
50+
"range end index {end} out of range for slice of length {len}",
51+
end: usize,
52+
len: usize,
53+
)
54+
}
5755

58-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
59-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
60-
#[track_caller]
61-
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
56+
if start > end {
57+
const_panic!(
58+
"slice index start is larger than end",
59+
"slice index starts at {start} but ends at {end}",
60+
start: usize,
61+
end: usize,
62+
)
63+
}
64+
65+
// Only reachable if the range was a `RangeInclusive` or a
66+
// `RangeToInclusive`, with `end == len`.
6267
const_panic!(
63-
"slice index start is larger than end",
64-
"slice index starts at {index} but ends at {end}",
65-
index: usize,
68+
"slice end index is out of range for slice",
69+
"range end index {end} out of range for slice of length {len}",
6670
end: usize,
71+
len: usize,
6772
)
6873
}
6974

@@ -341,7 +346,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
341346
// SAFETY: `self` is checked to be valid and in bounds above.
342347
unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) }
343348
} else {
344-
slice_end_index_len_fail(self.end(), slice.len())
349+
slice_index_fail(self.start(), self.end(), slice.len())
345350
}
346351
}
347352

@@ -351,7 +356,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
351356
// SAFETY: `self` is checked to be valid and in bounds above.
352357
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
353358
} else {
354-
slice_end_index_len_fail(self.end(), slice.len())
359+
slice_index_fail(self.start(), self.end(), slice.len())
355360
}
356361
}
357362
}
@@ -436,26 +441,27 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
436441
#[inline(always)]
437442
fn index(self, slice: &[T]) -> &[T] {
438443
// Using checked_sub is a safe way to get `SubUnchecked` in MIR
439-
let Some(new_len) = usize::checked_sub(self.end, self.start) else {
440-
slice_index_order_fail(self.start, self.end)
441-
};
442-
if self.end > slice.len() {
443-
slice_end_index_len_fail(self.end, slice.len());
444+
if let Some(new_len) = usize::checked_sub(self.end, self.start)
445+
&& self.end <= slice.len()
446+
{
447+
// SAFETY: `self` is checked to be valid and in bounds above.
448+
unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
449+
} else {
450+
slice_index_fail(self.start, self.end, slice.len())
444451
}
445-
// SAFETY: `self` is checked to be valid and in bounds above.
446-
unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
447452
}
448453

449454
#[inline]
450455
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
451-
let Some(new_len) = usize::checked_sub(self.end, self.start) else {
452-
slice_index_order_fail(self.start, self.end)
453-
};
454-
if self.end > slice.len() {
455-
slice_end_index_len_fail(self.end, slice.len());
456+
// Using checked_sub is a safe way to get `SubUnchecked` in MIR
457+
if let Some(new_len) = usize::checked_sub(self.end, self.start)
458+
&& self.end <= slice.len()
459+
{
460+
// SAFETY: `self` is checked to be valid and in bounds above.
461+
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) }
462+
} else {
463+
slice_index_fail(self.start, self.end, slice.len())
456464
}
457-
// SAFETY: `self` is checked to be valid and in bounds above.
458-
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) }
459465
}
460466
}
461467

@@ -567,7 +573,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
567573
#[inline]
568574
fn index(self, slice: &[T]) -> &[T] {
569575
if self.start > slice.len() {
570-
slice_start_index_len_fail(self.start, slice.len());
576+
slice_index_fail(self.start, slice.len(), slice.len())
571577
}
572578
// SAFETY: `self` is checked to be valid and in bounds above.
573579
unsafe { &*self.get_unchecked(slice) }
@@ -576,7 +582,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
576582
#[inline]
577583
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
578584
if self.start > slice.len() {
579-
slice_start_index_len_fail(self.start, slice.len());
585+
slice_index_fail(self.start, slice.len(), slice.len())
580586
}
581587
// SAFETY: `self` is checked to be valid and in bounds above.
582588
unsafe { &mut *self.get_unchecked_mut(slice) }
@@ -690,16 +696,16 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
690696

691697
#[inline]
692698
fn index(self, slice: &[T]) -> &[T] {
693-
if *self.end() == usize::MAX {
694-
slice_end_index_overflow_fail();
699+
if *self.end() >= slice.len() {
700+
slice_index_fail(self.start, self.end, slice.len())
695701
}
696702
self.into_slice_range().index(slice)
697703
}
698704

699705
#[inline]
700706
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
701-
if *self.end() == usize::MAX {
702-
slice_end_index_overflow_fail();
707+
if *self.end() >= slice.len() {
708+
slice_index_fail(self.start, self.end, slice.len())
703709
}
704710
self.into_slice_range().index_mut(slice)
705711
}
@@ -861,19 +867,25 @@ where
861867
};
862868

863869
let end = match range.end_bound() {
864-
ops::Bound::Included(end) => {
865-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
866-
}
870+
ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len),
871+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
872+
ops::Bound::Included(&end) => end + 1,
873+
874+
ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
867875
ops::Bound::Excluded(&end) => end,
868876
ops::Bound::Unbounded => len,
869877
};
870878

871-
if start > end {
872-
slice_index_order_fail(start, end);
873-
}
874-
if end > len {
875-
slice_end_index_len_fail(end, len);
876-
}
879+
let start = match range.start_bound() {
880+
ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len),
881+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
882+
ops::Bound::Excluded(&start) => start + 1,
883+
884+
ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
885+
ops::Bound::Included(&start) => start,
886+
887+
ops::Bound::Unbounded => 0,
888+
};
877889

878890
ops::Range { start, end }
879891
}
@@ -982,13 +994,26 @@ pub(crate) fn into_slice_range(
982994
len: usize,
983995
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
984996
) -> ops::Range<usize> {
985-
use ops::Bound;
997+
let end = match end {
998+
ops::Bound::Included(end) if end >= len => slice_index_fail(0, end, len),
999+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
1000+
ops::Bound::Included(end) => end + 1,
1001+
1002+
ops::Bound::Excluded(end) if end > len => slice_index_fail(0, end, len),
1003+
ops::Bound::Excluded(end) => end,
1004+
1005+
ops::Bound::Unbounded => len,
1006+
};
1007+
9861008
let start = match start {
987-
Bound::Included(start) => start,
988-
Bound::Excluded(start) => {
989-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
990-
}
991-
Bound::Unbounded => 0,
1009+
ops::Bound::Excluded(start) if start >= end => slice_index_fail(start, end, len),
1010+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
1011+
ops::Bound::Excluded(start) => start + 1,
1012+
1013+
ops::Bound::Included(start) if start > end => slice_index_fail(start, end, len),
1014+
ops::Bound::Included(start) => start,
1015+
1016+
ops::Bound::Unbounded => 0,
9921017
};
9931018

9941019
let end = match end {

library/coretests/tests/slice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,7 @@ mod slice_index {
15131513
data: [0; 1];
15141514

15151515
bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)];
1516-
message: "maximum usize";
1516+
message: "out of range";
15171517
}
15181518
} // panic_cases!
15191519
}

tests/codegen-llvm/integer-overflow.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub struct S1<'a> {
1010
// CHECK-LABEL: @slice_no_index_order
1111
#[no_mangle]
1212
pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] {
13-
// CHECK-NOT: slice_index_order_fail
13+
// CHECK-NOT: slice_index_fail
1414
let d = &s.data[s.position..s.position + n];
1515
s.position += n;
1616
return d;
@@ -19,6 +19,6 @@ pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] {
1919
// CHECK-LABEL: @test_check
2020
#[no_mangle]
2121
pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] {
22-
// CHECK: slice_index_order_fail
22+
// CHECK: slice_index_fail
2323
&s.data[x..y]
2424
}

tests/codegen-llvm/issues/issue-27130.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#[no_mangle]
77
pub fn trim_in_place(a: &mut &[u8]) {
88
while a.first() == Some(&42) {
9-
// CHECK-NOT: slice_index_order_fail
9+
// CHECK-NOT: slice_index_fail
1010
*a = &a[1..];
1111
}
1212
}
@@ -15,7 +15,7 @@ pub fn trim_in_place(a: &mut &[u8]) {
1515
#[no_mangle]
1616
pub fn trim_in_place2(a: &mut &[u8]) {
1717
while let Some(&42) = a.first() {
18-
// CHECK-NOT: slice_index_order_fail
18+
// CHECK-NOT: slice_index_fail
1919
*a = &a[2..];
2020
}
2121
}

tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,81 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] {
44
debug slice => _1;
55
debug index => _2;
66
let mut _0: &[u32];
7+
let mut _3: usize;
8+
let mut _4: usize;
79
scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) {
10+
scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::index) {
11+
let mut _7: usize;
12+
let mut _8: bool;
13+
let mut _9: *const [u32];
14+
let _12: *const [u32];
15+
let mut _13: usize;
16+
let mut _14: !;
17+
scope 3 (inlined core::num::<impl usize>::checked_sub) {
18+
let mut _5: bool;
19+
let mut _6: usize;
20+
}
21+
scope 4 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
22+
let _10: *const u32;
23+
scope 5 {
24+
let _11: *const u32;
25+
scope 6 {
26+
}
27+
}
28+
}
29+
}
830
}
931

1032
bb0: {
11-
_0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue];
33+
_3 = move (_2.0: usize);
34+
_4 = move (_2.1: usize);
35+
StorageLive(_5);
36+
_5 = Lt(copy _4, copy _3);
37+
switchInt(move _5) -> [0: bb1, otherwise: bb4];
1238
}
1339

1440
bb1: {
41+
_6 = SubUnchecked(copy _4, copy _3);
42+
StorageDead(_5);
43+
StorageLive(_8);
44+
StorageLive(_7);
45+
_7 = PtrMetadata(copy _1);
46+
_8 = Le(copy _4, move _7);
47+
switchInt(move _8) -> [0: bb2, otherwise: bb3];
48+
}
49+
50+
bb2: {
51+
StorageDead(_7);
52+
goto -> bb5;
53+
}
54+
55+
bb3: {
56+
StorageDead(_7);
57+
StorageLive(_12);
58+
StorageLive(_9);
59+
_9 = &raw const (*_1);
60+
StorageLive(_10);
61+
StorageLive(_11);
62+
_10 = copy _9 as *const u32 (PtrToPtr);
63+
_11 = Offset(copy _10, copy _3);
64+
_12 = *const [u32] from (copy _11, copy _6);
65+
StorageDead(_11);
66+
StorageDead(_10);
67+
StorageDead(_9);
68+
_0 = &(*_12);
69+
StorageDead(_12);
70+
StorageDead(_8);
1571
return;
1672
}
73+
74+
bb4: {
75+
StorageDead(_5);
76+
goto -> bb5;
77+
}
78+
79+
bb5: {
80+
StorageLive(_13);
81+
_13 = PtrMetadata(copy _1);
82+
_14 = core::slice::index::slice_index_fail(move _3, move _4, move _13) -> unwind continue;
83+
}
1784
}

0 commit comments

Comments
 (0)