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() -> ! {
106105 panic ! ( "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 = ptr as * 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 = ptr as * 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 {
110150 use 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]
204244 fn 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]
210250 fn 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.
229273 crate :: 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 {
265309 fn get ( self , slice : & [ T ] ) -> Option < & [ T ] > {
266310 if 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 {
270314 None
271315 }
@@ -275,7 +319,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
275319 fn get_mut ( self , slice : & mut [ T ] ) -> Option < & mut [ T ] > {
276320 if 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 {
280324 None
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]
311355 fn index ( self , slice : & [ T ] ) -> & [ T ] {
312356 if 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 {
316360 slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
317361 }
@@ -321,7 +365,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
321365 fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
322366 if 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 {
326370 slice_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]
340384 fn 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]
350397 fn 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.
375424 unsafe {
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.
393444 unsafe {
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) ]
400451 fn 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 ( ) {
404457 slice_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]
411464 fn 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 ( ) {
415469 slice_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
0 commit comments