2
2
3
3
use crate :: intrinsics:: const_eval_select;
4
4
use crate :: ops;
5
- use crate :: ptr;
6
5
use crate :: ub_checks:: assert_unsafe_precondition;
7
6
8
7
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -106,6 +105,47 @@ const fn slice_end_index_overflow_fail() -> ! {
106
105
panic ! ( "attempted to index slice up to maximum usize" ) ;
107
106
}
108
107
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
+
109
149
mod private_slice_index {
110
150
use super :: ops;
111
151
#[ stable( feature = "slice_get_slice" , since = "1.28.0" ) ]
@@ -203,13 +243,17 @@ unsafe impl<T> SliceIndex<[T]> for usize {
203
243
#[ inline]
204
244
fn get ( self , slice : & [ T ] ) -> Option < & T > {
205
245
// 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 }
207
247
}
208
248
209
249
#[ inline]
210
250
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
+ }
213
257
}
214
258
215
259
#[ inline]
@@ -227,7 +271,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
227
271
// Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the
228
272
// precondition of this function twice.
229
273
crate :: intrinsics:: assume ( self < slice. len ( ) ) ;
230
- slice . as_ptr ( ) . add ( self )
274
+ get_noubcheck ( slice , self )
231
275
}
232
276
}
233
277
@@ -239,7 +283,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
239
283
( this: usize = self , len: usize = slice. len( ) ) => this < len
240
284
) ;
241
285
// SAFETY: see comments for `get_unchecked` above.
242
- unsafe { slice . as_mut_ptr ( ) . add ( self ) }
286
+ unsafe { get_mut_noubcheck ( slice , self ) }
243
287
}
244
288
245
289
#[ inline]
@@ -265,7 +309,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
265
309
fn get ( self , slice : & [ T ] ) -> Option < & [ T ] > {
266
310
if self . end ( ) <= slice. len ( ) {
267
311
// 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 ( ) ) ) }
269
313
} else {
270
314
None
271
315
}
@@ -275,7 +319,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
275
319
fn get_mut ( self , slice : & mut [ T ] ) -> Option < & mut [ T ] > {
276
320
if self . end ( ) <= slice. len ( ) {
277
321
// 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 ( ) ) ) }
279
323
} else {
280
324
None
281
325
}
@@ -292,7 +336,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
292
336
// cannot be longer than `isize::MAX`. They also guarantee that
293
337
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
294
338
// 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 ( ) ) }
296
340
}
297
341
298
342
#[ inline]
@@ -304,14 +348,14 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
304
348
) ;
305
349
306
350
// 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 ( ) ) }
308
352
}
309
353
310
354
#[ inline]
311
355
fn index ( self , slice : & [ T ] ) -> & [ T ] {
312
356
if self . end ( ) <= slice. len ( ) {
313
357
// 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 ( ) ) }
315
359
} else {
316
360
slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
317
361
}
@@ -321,7 +365,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
321
365
fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
322
366
if self . end ( ) <= slice. len ( ) {
323
367
// 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 ( ) ) }
325
369
} else {
326
370
slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
327
371
}
@@ -338,21 +382,26 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
338
382
339
383
#[ inline]
340
384
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
+ {
344
389
// 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
346
393
}
347
394
}
348
395
349
396
#[ inline]
350
397
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
+ {
354
401
// 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
356
405
}
357
406
}
358
407
@@ -373,8 +422,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
373
422
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
374
423
// so the call to `add` is safe and the length calculation cannot overflow.
375
424
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)
378
429
}
379
430
}
380
431
@@ -391,31 +442,34 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
391
442
) ;
392
443
// SAFETY: see comments for `get_unchecked` above.
393
444
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)
396
447
}
397
448
}
398
449
399
450
#[ inline( always) ]
400
451
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 ( ) {
404
457
slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
405
458
}
406
459
// 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 ) }
408
461
}
409
462
410
463
#[ inline]
411
464
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 ( ) {
415
469
slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
416
470
}
417
471
// 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 ) }
419
473
}
420
474
}
421
475
0 commit comments