22
33use crate :: intrinsics:: const_eval_select;
44use crate :: ops;
5- use crate :: ptr;
65use crate :: ub_checks:: assert_unsafe_precondition;
76
87#[ stable( feature ="rust1" , since ="1.0.0" ) ]
@@ -106,6 +105,47 @@ const fn slice_end_index_overflow_fail() -> ! {
106105panic ! ( "attempted to index slice up to maximum usize" ) ;
107106}
108107
108+ // The UbChecks are great for catching bugs in the unsafe methods, but including
109+ // them in safe indexing is unnecessary and hurts inlining and debug runtime perf.
110+ // Both the safe and unsafe public methods share these helpers,
111+ // which use intrinsics directly to get *no* extra checks.
112+
113+ #[ inline( always) ]
114+ const unsafe fn get_noubcheck < T > ( ptr : * const [ T ] , index : usize ) ->* const T {
115+ let ptr = ptras * const T ;
116+ // SAFETY: The caller already checked these preconditions
117+ unsafe { crate :: intrinsics:: offset ( ptr, index) }
118+ }
119+
120+ #[ inline( always) ]
121+ const unsafe fn get_mut_noubcheck < T > ( ptr : * mut [ T ] , index : usize ) ->* mut T {
122+ let ptr = ptras * mut T ;
123+ // SAFETY: The caller already checked these preconditions
124+ unsafe { crate :: intrinsics:: offset ( ptr, index) }
125+ }
126+
127+ #[ inline( always) ]
128+ const unsafe fn get_offset_len_noubcheck < T > (
129+ ptr : * const [ T ] ,
130+ offset : usize ,
131+ len : usize ,
132+ ) ->* const [ T ] {
133+ // SAFETY: The caller already checked these preconditions
134+ let ptr =unsafe { get_noubcheck ( ptr, offset) } ;
135+ crate :: intrinsics:: aggregate_raw_ptr ( ptr, len)
136+ }
137+
138+ #[ inline( always) ]
139+ const unsafe fn get_offset_len_mut_noubcheck < T > (
140+ ptr : * mut [ T ] ,
141+ offset : usize ,
142+ len : usize ,
143+ ) ->* mut [ T ] {
144+ // SAFETY: The caller already checked these preconditions
145+ let ptr =unsafe { get_mut_noubcheck ( ptr, offset) } ;
146+ crate :: intrinsics:: aggregate_raw_ptr ( ptr, len)
147+ }
148+
109149mod private_slice_index{
110150use super :: ops;
111151#[ stable( feature ="slice_get_slice" , since ="1.28.0" ) ]
@@ -203,13 +243,17 @@ unsafe impl<T> SliceIndex<[T]> for usize {
203243#[ inline]
204244fn get ( self , slice : & [ T ] ) ->Option < & T > {
205245// SAFETY: `self` is checked to be in bounds.
206- if self < slice. len ( ) { unsafe { Some ( & * self . get_unchecked ( slice) ) } } else { None }
246+ if self < slice. len ( ) { unsafe { Some ( & * get_noubcheck ( slice, self ) ) } } else { None }
207247}
208248
209249#[ inline]
210250fn get_mut ( self , slice : & mut [ T ] ) ->Option < & mut T > {
211- // SAFETY: `self` is checked to be in bounds.
212- if self < slice. len ( ) { unsafe { Some ( & mut * self . get_unchecked_mut ( slice) ) } } else { None }
251+ if self < slice. len ( ) {
252+ // SAFETY: `self` is checked to be in bounds.
253+ unsafe { Some ( & mut * get_mut_noubcheck ( slice, self ) ) }
254+ } else {
255+ None
256+ }
213257}
214258
215259#[ inline]
@@ -227,7 +271,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
227271// Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the
228272// precondition of this function twice.
229273crate :: intrinsics:: assume ( self < slice. len ( ) ) ;
230- slice . as_ptr ( ) . add ( self )
274+ get_noubcheck ( slice , self )
231275}
232276}
233277
@@ -239,7 +283,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
239283( this: usize =self , len: usize = slice. len( ) ) => this < len
240284) ;
241285// SAFETY: see comments for `get_unchecked` above.
242- unsafe { slice . as_mut_ptr ( ) . add ( self ) }
286+ unsafe { get_mut_noubcheck ( slice , self ) }
243287}
244288
245289#[ inline]
@@ -265,7 +309,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
265309fn get ( self , slice : & [ T ] ) ->Option < & [ T ] > {
266310if self . end ( ) <= slice. len ( ) {
267311// SAFETY: `self` is checked to be valid and in bounds above.
268- unsafe { Some ( & * self . get_unchecked ( slice ) ) }
312+ unsafe { Some ( & * get_offset_len_noubcheck ( slice , self . start ( ) , self . len ( ) ) ) }
269313} else {
270314None
271315}
@@ -275,7 +319,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
275319fn get_mut ( self , slice : & mut [ T ] ) ->Option < & mut [ T ] > {
276320if self . end ( ) <= slice. len ( ) {
277321// SAFETY: `self` is checked to be valid and in bounds above.
278- unsafe { Some ( & mut * self . get_unchecked_mut ( slice ) ) }
322+ unsafe { Some ( & mut * get_offset_len_mut_noubcheck ( slice , self . start ( ) , self . len ( ) ) ) }
279323} else {
280324None
281325}
@@ -292,7 +336,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
292336// cannot be longer than `isize::MAX`. They also guarantee that
293337// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
294338// so the call to `add` is safe.
295- unsafe { ptr :: slice_from_raw_parts ( slice. as_ptr ( ) . add ( self . start ( ) ) , self . len ( ) ) }
339+ unsafe { get_offset_len_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
296340}
297341
298342#[ inline]
@@ -304,14 +348,14 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
304348) ;
305349
306350// SAFETY: see comments for `get_unchecked` above.
307- unsafe { ptr :: slice_from_raw_parts_mut ( slice. as_mut_ptr ( ) . add ( self . start ( ) ) , self . len ( ) ) }
351+ unsafe { get_offset_len_mut_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
308352}
309353
310354#[ inline]
311355fn index ( self , slice : & [ T ] ) ->& [ T ] {
312356if self . end ( ) <= slice. len ( ) {
313357// SAFETY: `self` is checked to be valid and in bounds above.
314- unsafe { & * self . get_unchecked ( slice ) }
358+ unsafe { & * get_offset_len_noubcheck ( slice , self . start ( ) , self . len ( ) ) }
315359} else {
316360slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
317361}
@@ -321,7 +365,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
321365fn index_mut ( self , slice : & mut [ T ] ) ->& mut [ T ] {
322366if self . end ( ) <= slice. len ( ) {
323367// SAFETY: `self` is checked to be valid and in bounds above.
324- unsafe { & mut * self . get_unchecked_mut ( slice ) }
368+ unsafe { & mut * get_offset_len_mut_noubcheck ( slice , self . start ( ) , self . len ( ) ) }
325369} else {
326370slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
327371}
@@ -338,21 +382,26 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
338382
339383#[ inline]
340384fn get ( self , slice : & [ T ] ) ->Option < & [ T ] > {
341- if self . start >self . end ||self . end > slice. len ( ) {
342- None
343- } else {
385+ // Using checked_sub is a safe way to get `SubUnchecked` in MIR
386+ if let Some ( new_len) = usize:: checked_sub ( self . end , self . start )
387+ &&self . end <= slice. len ( )
388+ {
344389// SAFETY: `self` is checked to be valid and in bounds above.
345- unsafe { Some ( & * self . get_unchecked ( slice) ) }
390+ unsafe { Some ( & * get_offset_len_noubcheck ( slice, self . start , new_len) ) }
391+ } else {
392+ None
346393}
347394}
348395
349396#[ inline]
350397fn get_mut ( self , slice : & mut [ T ] ) ->Option < & mut [ T ] > {
351- if self . start > self . end || self . end > slice . len ( ) {
352- None
353- } else {
398+ if let Some ( new_len ) = usize :: checked_sub ( self . end , self . start )
399+ && self . end <= slice . len ( )
400+ {
354401// SAFETY: `self` is checked to be valid and in bounds above.
355- unsafe { Some ( & mut * self . get_unchecked_mut ( slice) ) }
402+ unsafe { Some ( & mut * get_offset_len_mut_noubcheck ( slice, self . start , new_len) ) }
403+ } else {
404+ None
356405}
357406}
358407
@@ -373,8 +422,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
373422// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
374423// so the call to `add` is safe and the length calculation cannot overflow.
375424unsafe {
376- let new_len =self . end . unchecked_sub ( self . start ) ;
377- ptr:: slice_from_raw_parts ( slice. as_ptr ( ) . add ( self . start ) , new_len)
425+ // Using the intrinsic avoids a superfluous UB check,
426+ // since the one on this method already checked `end >= start`.
427+ let new_len =crate :: intrinsics:: unchecked_sub ( self . end , self . start ) ;
428+ get_offset_len_noubcheck ( slice, self . start , new_len)
378429}
379430}
380431
@@ -391,31 +442,34 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
391442) ;
392443// SAFETY: see comments for `get_unchecked` above.
393444unsafe {
394- let new_len =self . end . unchecked_sub ( self . start ) ;
395- ptr :: slice_from_raw_parts_mut ( slice. as_mut_ptr ( ) . add ( self . start ) , new_len)
445+ let new_len =crate :: intrinsics :: unchecked_sub ( self . end , self . start ) ;
446+ get_offset_len_mut_noubcheck ( slice, self . start , new_len)
396447}
397448}
398449
399450#[ inline( always) ]
400451fn index ( self , slice : & [ T ] ) ->& [ T ] {
401- if self . start >self . end {
402- slice_index_order_fail ( self . start , self . end ) ;
403- } else if self . end > slice. len ( ) {
452+ // Using checked_sub is a safe way to get `SubUnchecked` in MIR
453+ let Some ( new_len) = usize:: checked_sub ( self . end , self . start ) else {
454+ slice_index_order_fail ( self . start , self . end )
455+ } ;
456+ if self . end > slice. len ( ) {
404457slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
405458}
406459// SAFETY: `self` is checked to be valid and in bounds above.
407- unsafe { & * self . get_unchecked ( slice) }
460+ unsafe { & * get_offset_len_noubcheck ( slice, self . start , new_len ) }
408461}
409462
410463#[ inline]
411464fn index_mut ( self , slice : & mut [ T ] ) ->& mut [ T ] {
412- if self . start >self . end {
413- slice_index_order_fail ( self . start , self . end ) ;
414- } else if self . end > slice. len ( ) {
465+ let Some ( new_len) = usize:: checked_sub ( self . end , self . start ) else {
466+ slice_index_order_fail ( self . start , self . end )
467+ } ;
468+ if self . end > slice. len ( ) {
415469slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
416470}
417471// SAFETY: `self` is checked to be valid and in bounds above.
418- unsafe { & mut * self . get_unchecked_mut ( slice) }
472+ unsafe { & mut * get_offset_len_mut_noubcheck ( slice, self . start , new_len ) }
419473}
420474}
421475