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,51 @@ 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 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
+
109
153
mod private_slice_index {
110
154
use super :: ops;
111
155
#[ stable( feature = "slice_get_slice" , since = "1.28.0" ) ]
@@ -203,13 +247,17 @@ unsafe impl<T> SliceIndex<[T]> for usize {
203
247
#[ inline]
204
248
fn get ( self , slice : & [ T ] ) -> Option < & T > {
205
249
// 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 }
207
251
}
208
252
209
253
#[ inline]
210
254
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
+ }
213
261
}
214
262
215
263
#[ inline]
@@ -227,7 +275,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
227
275
// Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the
228
276
// precondition of this function twice.
229
277
crate :: intrinsics:: assume ( self < slice. len ( ) ) ;
230
- slice . as_ptr ( ) . add ( self )
278
+ get_noubcheck ( slice , self )
231
279
}
232
280
}
233
281
@@ -239,7 +287,7 @@ unsafe impl<T> SliceIndex<[T]> for usize {
239
287
( this: usize = self , len: usize = slice. len( ) ) => this < len
240
288
) ;
241
289
// SAFETY: see comments for `get_unchecked` above.
242
- unsafe { slice . as_mut_ptr ( ) . add ( self ) }
290
+ unsafe { get_mut_noubcheck ( slice , self ) }
243
291
}
244
292
245
293
#[ inline]
@@ -265,7 +313,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
265
313
fn get ( self , slice : & [ T ] ) -> Option < & [ T ] > {
266
314
if self . end ( ) <= slice. len ( ) {
267
315
// 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 ( ) ) ) }
269
317
} else {
270
318
None
271
319
}
@@ -275,7 +323,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
275
323
fn get_mut ( self , slice : & mut [ T ] ) -> Option < & mut [ T ] > {
276
324
if self . end ( ) <= slice. len ( ) {
277
325
// 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 ( ) ) ) }
279
327
} else {
280
328
None
281
329
}
@@ -292,7 +340,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
292
340
// cannot be longer than `isize::MAX`. They also guarantee that
293
341
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
294
342
// 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 ( ) ) }
296
344
}
297
345
298
346
#[ inline]
@@ -304,14 +352,14 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
304
352
) ;
305
353
306
354
// 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 ( ) ) }
308
356
}
309
357
310
358
#[ inline]
311
359
fn index ( self , slice : & [ T ] ) -> & [ T ] {
312
360
if self . end ( ) <= slice. len ( ) {
313
361
// 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 ( ) ) }
315
363
} else {
316
364
slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
317
365
}
@@ -321,7 +369,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
321
369
fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
322
370
if self . end ( ) <= slice. len ( ) {
323
371
// 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 ( ) ) }
325
373
} else {
326
374
slice_end_index_len_fail ( self . end ( ) , slice. len ( ) )
327
375
}
@@ -338,21 +386,26 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
338
386
339
387
#[ inline]
340
388
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
+ {
344
393
// 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
346
397
}
347
398
}
348
399
349
400
#[ inline]
350
401
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
+ {
354
405
// 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
356
409
}
357
410
}
358
411
@@ -373,8 +426,10 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
373
426
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
374
427
// so the call to `add` is safe and the length calculation cannot overflow.
375
428
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)
378
433
}
379
434
}
380
435
@@ -391,31 +446,34 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
391
446
) ;
392
447
// SAFETY: see comments for `get_unchecked` above.
393
448
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)
396
451
}
397
452
}
398
453
399
454
#[ inline( always) ]
400
455
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 ( ) {
404
461
slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
405
462
}
406
463
// 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 ) }
408
465
}
409
466
410
467
#[ inline]
411
468
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 ( ) {
415
473
slice_end_index_len_fail ( self . end , slice. len ( ) ) ;
416
474
}
417
475
// 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 ) }
419
477
}
420
478
}
421
479
0 commit comments