@@ -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