@@ -34,53 +34,44 @@ 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
70- #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
71- #[cfg_attr(feature = "panic_immediate_abort", inline)]
72- #[track_caller]
73- const fn slice_start_index_overflow_fail() -> ! {
74- panic!("attempted to index slice from after maximum usize");
75- }
76-
77- #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
78- #[cfg_attr(feature = "panic_immediate_abort", inline)]
79- #[track_caller]
80- const fn slice_end_index_overflow_fail() -> ! {
81- panic!("attempted to index slice up to maximum usize");
82- }
83-
8475// The UbChecks are great for catching bugs in the unsafe methods, but including
8576// them in safe indexing is unnecessary and hurts inlining and debug runtime perf.
8677// Both the safe and unsafe public methods share these helpers,
@@ -341,7 +332,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
341332 // SAFETY: `self` is checked to be valid and in bounds above.
342333 unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) }
343334 } else {
344- slice_end_index_len_fail( self.end(), slice.len())
335+ slice_index_fail(self.start(), self.end(), slice.len())
345336 }
346337 }
347338
@@ -351,7 +342,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
351342 // SAFETY: `self` is checked to be valid and in bounds above.
352343 unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
353344 } else {
354- slice_end_index_len_fail( self.end(), slice.len())
345+ slice_index_fail(self.start(), self.end(), slice.len())
355346 }
356347 }
357348}
@@ -436,26 +427,27 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
436427 #[inline(always)]
437428 fn index(self, slice: &[T]) -> &[T] {
438429 // 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());
430+ if let Some(new_len) = usize::checked_sub(self.end, self.start)
431+ && self.end <= slice.len()
432+ {
433+ // SAFETY: `self` is checked to be valid and in bounds above.
434+ unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
435+ } else {
436+ slice_index_fail(self.start, self.end, slice.len())
444437 }
445- // SAFETY: `self` is checked to be valid and in bounds above.
446- unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
447438 }
448439
449440 #[inline]
450441 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());
442+ // Using checked_sub is a safe way to get `SubUnchecked` in MIR
443+ if let Some(new_len) = usize::checked_sub(self.end, self.start)
444+ && self.end <= slice.len()
445+ {
446+ // SAFETY: `self` is checked to be valid and in bounds above.
447+ unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) }
448+ } else {
449+ slice_index_fail(self.start, self.end, slice.len())
456450 }
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) }
459451 }
460452}
461453
@@ -567,7 +559,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
567559 #[inline]
568560 fn index(self, slice: &[T]) -> &[T] {
569561 if self.start > slice.len() {
570- slice_start_index_len_fail (self.start, slice.len());
562+ slice_index_fail (self.start, slice.len(), slice.len())
571563 }
572564 // SAFETY: `self` is checked to be valid and in bounds above.
573565 unsafe { &*self.get_unchecked(slice) }
@@ -576,7 +568,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
576568 #[inline]
577569 fn index_mut(self, slice: &mut [T]) -> &mut [T] {
578570 if self.start > slice.len() {
579- slice_start_index_len_fail (self.start, slice.len());
571+ slice_index_fail (self.start, slice.len(), slice.len())
580572 }
581573 // SAFETY: `self` is checked to be valid and in bounds above.
582574 unsafe { &mut *self.get_unchecked_mut(slice) }
@@ -690,18 +682,32 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
690682
691683 #[inline]
692684 fn index(self, slice: &[T]) -> &[T] {
693- if *self.end() == usize::MAX {
694- slice_end_index_overflow_fail();
685+ let Self { mut start, mut end, exhausted } = self;
686+ let len = slice.len();
687+ if end < len {
688+ end = end + 1;
689+ start = if exhausted { end } else { start };
690+ if let Some(new_len) = usize::checked_sub(end, start) {
691+ // SAFETY: `self` is checked to be valid and in bounds above.
692+ unsafe { return &*get_offset_len_noubcheck(slice, start, new_len) }
693+ }
695694 }
696- self.into_slice_range().index(slice )
695+ slice_index_fail(start, end, slice.len() )
697696 }
698697
699698 #[inline]
700699 fn index_mut(self, slice: &mut [T]) -> &mut [T] {
701- if *self.end() == usize::MAX {
702- slice_end_index_overflow_fail();
700+ let Self { mut start, mut end, exhausted } = self;
701+ let len = slice.len();
702+ if end < len {
703+ end = end + 1;
704+ start = if exhausted { end } else { start };
705+ if let Some(new_len) = usize::checked_sub(end, start) {
706+ // SAFETY: `self` is checked to be valid and in bounds above.
707+ unsafe { return &mut *get_offset_len_mut_noubcheck(slice, start, new_len) }
708+ }
703709 }
704- self.into_slice_range().index_mut(slice )
710+ slice_index_fail(start, end, slice.len() )
705711 }
706712}
707713
@@ -852,28 +858,26 @@ where
852858{
853859 let len = bounds.end;
854860
855- let start = match range.start_bound() {
856- ops::Bound::Included(&start) => start,
857- ops::Bound::Excluded(start) => {
858- start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
859- }
860- ops::Bound::Unbounded => 0,
861- };
862-
863861 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- }
862+ ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len),
863+ // Cannot overflow because `end < len` implies `end < usize::MAX`.
864+ ops::Bound::Included(&end) => end + 1,
865+
866+ ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
867867 ops::Bound::Excluded(&end) => end,
868868 ops::Bound::Unbounded => len,
869869 };
870870
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- }
871+ let start = match range.start_bound() {
872+ ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len),
873+ // Cannot overflow because `start < end` implies `start < usize::MAX`.
874+ ops::Bound::Excluded(&start) => start + 1,
875+
876+ ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
877+ ops::Bound::Included(&start) => start,
878+
879+ ops::Bound::Unbounded => 0,
880+ };
877881
878882 ops::Range { start, end }
879883}
@@ -982,25 +986,27 @@ pub(crate) fn into_slice_range(
982986 len: usize,
983987 (start, end): (ops::Bound<usize>, ops::Bound<usize>),
984988) -> ops::Range<usize> {
985- use ops::Bound;
986- 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,
992- };
993-
994989 let end = match end {
995- Bound::Included(end) => {
996- end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
997- }
998- Bound::Excluded(end) => end,
999- Bound::Unbounded => len,
990+ ops::Bound::Included(end) if end >= len => slice_index_fail(0, end, len),
991+ // Cannot overflow because `end < len` implies `end < usize::MAX`.
992+ ops::Bound::Included(end) => end + 1,
993+
994+ ops::Bound::Excluded(end) if end > len => slice_index_fail(0, end, len),
995+ ops::Bound::Excluded(end) => end,
996+
997+ ops::Bound::Unbounded => len,
1000998 };
1001999
1002- // Don't bother with checking `start < end` and `end <= len`
1003- // since these checks are handled by `Range` impls
1000+ let start = match start {
1001+ ops::Bound::Excluded(start) if start >= end => slice_index_fail(start, end, len),
1002+ // Cannot overflow because `start < end` implies `start < usize::MAX`.
1003+ ops::Bound::Excluded(start) => start + 1,
1004+
1005+ ops::Bound::Included(start) if start > end => slice_index_fail(start, end, len),
1006+ ops::Bound::Included(start) => start,
1007+
1008+ ops::Bound::Unbounded => 0,
1009+ };
10041010
10051011 start..end
10061012}
0 commit comments