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,51 @@ 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 compile-time.
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+ unsafe {
135+ let ptr = get_noubcheck ( ptr, offset) ;
136+ crate :: intrinsics:: aggregate_raw_ptr ( ptr, len)
137+ }
138+ }
139+
140+ #[ inline( always) ]
141+ const unsafe fn get_offset_len_mut_noubcheck < T > (
142+ ptr : * mut [ T ] ,
143+ offset : usize ,
144+ len : usize ,
145+ ) -> * mut [ T ] {
146+ // SAFETY: The caller already checked these preconditions
147+ unsafe {
148+ let ptr = get_mut_noubcheck ( ptr, offset) ;
149+ crate :: intrinsics:: aggregate_raw_ptr ( ptr, len)
150+ }
151+ }
152+
109153mod private_slice_index {
110154 use super :: ops;
111155 #[ stable( feature = "slice_get_slice" , since = "1.28.0" ) ]
@@ -203,13 +247,17 @@ unsafe impl<T> SliceIndex<[T]> for usize {
203247 #[ inline]
204248 fn get ( self , slice : & [ T ] ) -> Option < & T > {
205249 // SAFETY: `self` is checked to be in bounds.
206- if self < slice. len ( ) { unsafe { Some ( & * self . get_unchecked ( slice) ) } } else { None }
250+ if self < slice. len ( ) { unsafe { Some ( & * get_noubcheck ( slice, self ) ) } } else { None }
207251 }
208252
209253 #[ inline]
210254 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 }
255+ if self < slice. len ( ) {
256+ // SAFETY: `self` is checked to be in bounds.
257+ unsafe { Some ( & mut * get_mut_noubcheck ( slice, self ) ) }
258+ } else {
259+ None
260+ }
213261 }
214262
215263 #[ inline]
@@ -227,7 +275,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
227275 // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the
228276 // precondition of this function twice.
229277 crate :: intrinsics:: assume ( self < slice. len ( ) ) ;
230- slice . as_ptr ( ) . add ( self )
278+ get_noubcheck ( slice , self )
231279 }
232280 }
233281
@@ -239,7 +287,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
239287 ( this: usize = self , len: usize = slice. len( ) ) => this < len
240288 ) ;
241289 // SAFETY: see comments for `get_unchecked` above.
242- unsafe { slice . as_mut_ptr ( ) . add ( self ) }
290+ unsafe { get_mut_noubcheck ( slice , self ) }
243291 }
244292
245293 #[ inline]
@@ -265,7 +313,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
265313 fn get ( self , slice : & [ T ] ) -> Option < & [ T ] > {
266314 if self . end ( ) <= slice. len ( ) {
267315 // SAFETY: `self` is checked to be valid and in bounds above.
268- unsafe { Some ( & * self . get_unchecked ( slice ) ) }
316+ unsafe { Some ( & * get_offset_len_noubcheck ( slice , self . start ( ) , self . len ( ) ) ) }
269317 } else {
270318 None
271319 }
@@ -275,7 +323,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
275323 fn get_mut ( self , slice : & mut [ T ] ) -> Option < & mut [ T ] > {
276324 if self . end ( ) <= slice. len ( ) {
277325 // SAFETY: `self` is checked to be valid and in bounds above.
278- unsafe { Some ( & mut * self . get_unchecked_mut ( slice ) ) }
326+ unsafe { Some ( & mut * get_offset_len_mut_noubcheck ( slice , self . start ( ) , self . len ( ) ) ) }
279327 } else {
280328 None
281329 }
@@ -292,7 +340,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
292340 // cannot be longer than `isize::MAX`. They also guarantee that
293341 // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
294342 // so the call to `add` is safe.
295- unsafe { ptr :: slice_from_raw_parts ( slice. as_ptr ( ) . add ( self . start ( ) ) , self . len ( ) ) }
343+ unsafe { get_offset_len_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
296344 }
297345
298346 #[ inline]
@@ -304,14 +352,14 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
304352 ) ;
305353
306354 // SAFETY: see comments for `get_unchecked` above.
307- unsafe { ptr :: slice_from_raw_parts_mut ( slice. as_mut_ptr ( ) . add ( self . start ( ) ) , self . len ( ) ) }
355+ unsafe { get_offset_len_mut_noubcheck ( slice, self . start ( ) , self . len ( ) ) }
308356 }
309357
310358 #[ inline]
311359 fn index ( self , slice : & [ T ] ) -> & [ T ] {
312360 if self . end ( ) <= slice. len ( ) {
313361 // SAFETY: `self` is checked to be valid and in bounds above.
314- unsafe { & * self . get_unchecked ( slice ) }
362+ unsafe { & * get_offset_len_noubcheck ( slice , self . start ( ) , self . len ( ) ) }
315363 } else {
316364 slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
317365 }
@@ -321,7 +369,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
321369 fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
322370 if self . end ( ) <= slice. len ( ) {
323371 // SAFETY: `self` is checked to be valid and in bounds above.
324- unsafe { & mut * self . get_unchecked_mut ( slice ) }
372+ unsafe { & mut * get_offset_len_mut_noubcheck ( slice , self . start ( ) , self . len ( ) ) }
325373 } else {
326374 slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
327375 }
@@ -338,21 +386,26 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
338386
339387 #[ inline]
340388 fn get ( self , slice : & [ T ] ) -> Option < & [ T ] > {
341- if self . start > self . end || self . end > slice. len ( ) {
342- None
343- } else {
389+ // Using checked_sub is a safe way to get `SubUnchecked` in MIR
390+ if let Some ( new_len) = usize:: checked_sub ( self . end , self . start )
391+ && self . end <= slice. len ( )
392+ {
344393 // SAFETY: `self` is checked to be valid and in bounds above.
345- unsafe { Some ( & * self . get_unchecked ( slice) ) }
394+ unsafe { Some ( & * get_offset_len_noubcheck ( slice, self . start , new_len) ) }
395+ } else {
396+ None
346397 }
347398 }
348399
349400 #[ inline]
350401 fn get_mut ( self , slice : & mut [ T ] ) -> Option < & mut [ T ] > {
351- if self . start > self . end || self . end > slice . len ( ) {
352- None
353- } else {
402+ if let Some ( new_len ) = usize :: checked_sub ( self . end , self . start )
403+ && self . end <= slice . len ( )
404+ {
354405 // SAFETY: `self` is checked to be valid and in bounds above.
355- unsafe { Some ( & mut * self . get_unchecked_mut ( slice) ) }
406+ unsafe { Some ( & mut * get_offset_len_mut_noubcheck ( slice, self . start , new_len) ) }
407+ } else {
408+ None
356409 }
357410 }
358411
@@ -373,8 +426,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
373426 // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
374427 // so the call to `add` is safe and the length calculation cannot overflow.
375428 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)
429+ // Using the intrinsic avoids a superfluous UB check,
430+ // since the one on this method already checked `end >= start`.
431+ let new_len = crate :: intrinsics:: unchecked_sub ( self . end , self . start ) ;
432+ get_offset_len_noubcheck ( slice, self . start , new_len)
378433 }
379434 }
380435
@@ -391,31 +446,34 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
391446 ) ;
392447 // SAFETY: see comments for `get_unchecked` above.
393448 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)
449+ let new_len = crate :: intrinsics :: unchecked_sub ( self . end , self . start ) ;
450+ get_offset_len_mut_noubcheck ( slice, self . start , new_len)
396451 }
397452 }
398453
399454 #[ inline( always) ]
400455 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 ( ) {
456+ // Using checked_sub is a safe way to get `SubUnchecked` in MIR
457+ let Some ( new_len) = usize:: checked_sub ( self . end , self . start ) else {
458+ slice_index_order_fail ( self . start , self . end )
459+ } ;
460+ if self . end > slice. len ( ) {
404461 slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
405462 }
406463 // SAFETY: `self` is checked to be valid and in bounds above.
407- unsafe { & * self . get_unchecked ( slice) }
464+ unsafe { & * get_offset_len_noubcheck ( slice, self . start , new_len ) }
408465 }
409466
410467 #[ inline]
411468 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 ( ) {
469+ let Some ( new_len) = usize:: checked_sub ( self . end , self . start ) else {
470+ slice_index_order_fail ( self . start , self . end )
471+ } ;
472+ if self . end > slice. len ( ) {
415473 slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
416474 }
417475 // SAFETY: `self` is checked to be valid and in bounds above.
418- unsafe { & mut * self . get_unchecked_mut ( slice) }
476+ unsafe { & mut * get_offset_len_mut_noubcheck ( slice, self . start , new_len ) }
419477 }
420478}
421479
0 commit comments