@@ -34,53 +34,44 @@ where
34
34
#[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) , cold) ]
35
35
#[ cfg_attr( feature = "panic_immediate_abort" , inline) ]
36
36
#[ 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
+ }
45
46
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
+ }
57
55
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`.
62
67
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}" ,
66
70
end: usize ,
71
+ len: usize ,
67
72
)
68
73
}
69
74
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
-
84
75
// The UbChecks are great for catching bugs in the unsafe methods, but including
85
76
// them in safe indexing is unnecessary and hurts inlining and debug runtime perf.
86
77
// Both the safe and unsafe public methods share these helpers,
@@ -341,7 +332,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
341
332
// SAFETY: `self` is checked to be valid and in bounds above.
342
333
unsafe { & * get_offset_len_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
343
334
} else {
344
- slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
335
+ slice_index_fail ( self . start ( ) , self . end ( ) , slice. len ( ) )
345
336
}
346
337
}
347
338
@@ -351,7 +342,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
351
342
// SAFETY: `self` is checked to be valid and in bounds above.
352
343
unsafe { & mut * get_offset_len_mut_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
353
344
} else {
354
- slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
345
+ slice_index_fail ( self . start ( ) , self . end ( ) , slice. len ( ) )
355
346
}
356
347
}
357
348
}
@@ -436,26 +427,27 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
436
427
#[ inline( always) ]
437
428
fn index ( self , slice : & [ T ] ) -> & [ T ] {
438
429
// 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 ( ) )
444
437
}
445
- // SAFETY: `self` is checked to be valid and in bounds above.
446
- unsafe { & * get_offset_len_noubcheck ( slice, self . start , new_len) }
447
438
}
448
439
449
440
#[ inline]
450
441
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 ( ) )
456
450
}
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) }
459
451
}
460
452
}
461
453
@@ -567,7 +559,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
567
559
#[ inline]
568
560
fn index ( self , slice : & [ T ] ) -> & [ T ] {
569
561
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 ( ) )
571
563
}
572
564
// SAFETY: `self` is checked to be valid and in bounds above.
573
565
unsafe { & * self . get_unchecked ( slice) }
@@ -576,7 +568,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
576
568
#[ inline]
577
569
fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
578
570
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 ( ) )
580
572
}
581
573
// SAFETY: `self` is checked to be valid and in bounds above.
582
574
unsafe { & mut * self . get_unchecked_mut ( slice) }
@@ -690,18 +682,32 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
690
682
691
683
#[ inline]
692
684
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
+ }
695
694
}
696
- self . into_slice_range ( ) . index ( slice )
695
+ slice_index_fail ( start , end , slice . len ( ) )
697
696
}
698
697
699
698
#[ inline]
700
699
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
+ }
703
709
}
704
- self . into_slice_range ( ) . index_mut ( slice )
710
+ slice_index_fail ( start , end , slice . len ( ) )
705
711
}
706
712
}
707
713
@@ -852,28 +858,26 @@ where
852
858
{
853
859
let len = bounds. end ;
854
860
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
-
863
861
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) ,
867
867
ops:: Bound :: Excluded ( & end) => end,
868
868
ops:: Bound :: Unbounded => len,
869
869
} ;
870
870
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
+ } ;
877
881
878
882
ops:: Range { start, end }
879
883
}
@@ -982,25 +986,27 @@ pub(crate) fn into_slice_range(
982
986
len : usize ,
983
987
( start, end) : ( ops:: Bound < usize > , ops:: Bound < usize > ) ,
984
988
) -> 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
-
994
989
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,
1000
998
} ;
1001
999
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
+ } ;
1004
1010
1005
1011
start..end
1006
1012
}
0 commit comments