@@ -2,6 +2,7 @@ use crate::ascii;
2
2
use crate :: cmp:: Ordering ;
3
3
use crate :: ffi:: c_char;
4
4
use crate :: fmt:: { self , Write } ;
5
+ use crate :: intrinsics;
5
6
use crate :: ops;
6
7
use crate :: slice;
7
8
use crate :: slice:: memchr;
@@ -384,21 +385,41 @@ impl CStr {
384
385
#[ must_use]
385
386
#[ stable( feature = "cstr_from_bytes" , since = "1.10.0" ) ]
386
387
#[ rustc_const_stable( feature = "const_cstr_unchecked" , since = "1.59.0" ) ]
388
+ #[ rustc_allow_const_fn_unstable( const_eval_select) ]
387
389
pub const unsafe fn from_bytes_with_nul_unchecked ( bytes : & [ u8 ] ) -> & CStr {
388
- // We're in a const fn, so this is the best we can do
389
- debug_assert ! ( !bytes. is_empty( ) && bytes[ bytes. len( ) - 1 ] == 0 ) ;
390
- // SAFETY: Calling an inner function with the same prerequisites.
391
- unsafe { Self :: _from_bytes_with_nul_unchecked ( bytes) }
392
- }
390
+ fn rt_impl ( bytes : & [ u8 ] ) -> & CStr {
391
+ // Chance at catching some UB at runtime with debug builds.
392
+ debug_assert ! ( !bytes. is_empty( ) && bytes[ bytes. len( ) - 1 ] == 0 ) ;
393
393
394
- #[ inline]
395
- const unsafe fn _from_bytes_with_nul_unchecked ( bytes : & [ u8 ] ) -> & CStr {
396
- // SAFETY: Casting to CStr is safe because its internal representation
397
- // is a [u8] too (safe only inside std).
398
- // Dereferencing the obtained pointer is safe because it comes from a
399
- // reference. Making a reference is then safe because its lifetime
400
- // is bound by the lifetime of the given `bytes`.
401
- unsafe { & * ( bytes as * const [ u8 ] as * const CStr ) }
394
+ // SAFETY: Casting to CStr is safe because its internal representation
395
+ // is a [u8] too (safe only inside std).
396
+ // Dereferencing the obtained pointer is safe because it comes from a
397
+ // reference. Making a reference is then safe because its lifetime
398
+ // is bound by the lifetime of the given `bytes`.
399
+ unsafe { & * ( bytes as * const [ u8 ] as * const CStr ) }
400
+ }
401
+
402
+ const fn const_impl ( bytes : & [ u8 ] ) -> & CStr {
403
+ // Saturating so that an empty slice panics in the assert with a good
404
+ // message, not here due to underflow.
405
+ let mut i = bytes. len ( ) . saturating_sub ( 1 ) ;
406
+ assert ! ( !bytes. is_empty( ) && bytes[ i] == 0 , "input was not nul-terminated" ) ;
407
+
408
+ // Ending null byte exists, skip to the rest.
409
+ while i != 0 {
410
+ i -= 1 ;
411
+ let byte = bytes[ i] ;
412
+ assert ! ( byte != 0 , "input contained interior nul" ) ;
413
+ }
414
+
415
+ // SAFETY: See `rt_impl` cast.
416
+ unsafe { & * ( bytes as * const [ u8 ] as * const CStr ) }
417
+ }
418
+
419
+ // SAFETY: The const and runtime versions have identical behavior
420
+ // unless the safety contract of `from_bytes_with_nul_unchecked` is
421
+ // violated, which is UB.
422
+ unsafe { intrinsics:: const_eval_select ( ( bytes, ) , const_impl, rt_impl) }
402
423
}
403
424
404
425
/// Returns the inner pointer to this C string.
0 commit comments