|
3 | 3 | use crate::cmp::Ordering; |
4 | 4 | use crate::error::Error; |
5 | 5 | use crate::ffi::c_char; |
| 6 | +use crate::intrinsics::const_eval_select; |
6 | 7 | use crate::iter::FusedIterator; |
7 | 8 | use crate::marker::PhantomData; |
8 | 9 | use crate::ptr::NonNull; |
9 | 10 | use crate::slice::memchr; |
10 | | -use crate::{fmt, intrinsics, ops, slice, str}; |
| 11 | +use crate::{fmt, ops, slice, str}; |
11 | 12 |
|
12 | 13 | // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link |
13 | 14 | // depends on where the item is being documented. however, since this is libcore, we can't |
@@ -411,37 +412,35 @@ impl CStr { |
411 | 412 | #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] |
412 | 413 | #[rustc_allow_const_fn_unstable(const_eval_select)] |
413 | 414 | pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { |
414 | | - #[inline] |
415 | | - fn rt_impl(bytes: &[u8]) -> &CStr { |
416 | | - // Chance at catching some UB at runtime with debug builds. |
417 | | - debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); |
418 | | - |
419 | | - // SAFETY: Casting to CStr is safe because its internal representation |
420 | | - // is a [u8] too (safe only inside std). |
421 | | - // Dereferencing the obtained pointer is safe because it comes from a |
422 | | - // reference. Making a reference is then safe because its lifetime |
423 | | - // is bound by the lifetime of the given `bytes`. |
424 | | - unsafe { &*(bytes as *const [u8] as *const CStr) } |
425 | | - } |
426 | | - |
427 | | - const fn const_impl(bytes: &[u8]) -> &CStr { |
428 | | - // Saturating so that an empty slice panics in the assert with a good |
429 | | - // message, not here due to underflow. |
430 | | - let mut i = bytes.len().saturating_sub(1); |
431 | | - assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated"); |
432 | | - |
433 | | - // Ending nul byte exists, skip to the rest. |
434 | | - while i != 0 { |
435 | | - i -= 1; |
436 | | - let byte = bytes[i]; |
437 | | - assert!(byte != 0, "input contained interior nul"); |
| 415 | + const_eval_select!( |
| 416 | + @capture { bytes: &[u8] } -> &CStr: |
| 417 | + if const { |
| 418 | + // Saturating so that an empty slice panics in the assert with a good |
| 419 | + // message, not here due to underflow. |
| 420 | + let mut i = bytes.len().saturating_sub(1); |
| 421 | + assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated"); |
| 422 | + |
| 423 | + // Ending nul byte exists, skip to the rest. |
| 424 | + while i != 0 { |
| 425 | + i -= 1; |
| 426 | + let byte = bytes[i]; |
| 427 | + assert!(byte != 0, "input contained interior nul"); |
| 428 | + } |
| 429 | + |
| 430 | + // SAFETY: See runtime cast comment below. |
| 431 | + unsafe { &*(bytes as *const [u8] as *const CStr) } |
| 432 | + } else { |
| 433 | + // Chance at catching some UB at runtime with debug builds. |
| 434 | + debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); |
| 435 | + |
| 436 | + // SAFETY: Casting to CStr is safe because its internal representation |
| 437 | + // is a [u8] too (safe only inside std). |
| 438 | + // Dereferencing the obtained pointer is safe because it comes from a |
| 439 | + // reference. Making a reference is then safe because its lifetime |
| 440 | + // is bound by the lifetime of the given `bytes`. |
| 441 | + unsafe { &*(bytes as *const [u8] as *const CStr) } |
438 | 442 | } |
439 | | - |
440 | | - // SAFETY: See `rt_impl` cast. |
441 | | - unsafe { &*(bytes as *const [u8] as *const CStr) } |
442 | | - } |
443 | | - |
444 | | - intrinsics::const_eval_select((bytes,), const_impl, rt_impl) |
| 443 | + ) |
445 | 444 | } |
446 | 445 |
|
447 | 446 | /// Returns the inner pointer to this C string. |
@@ -735,29 +734,27 @@ impl AsRef<CStr> for CStr { |
735 | 734 | #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))] |
736 | 735 | #[rustc_allow_const_fn_unstable(const_eval_select)] |
737 | 736 | const unsafe fn strlen(ptr: *const c_char) -> usize { |
738 | | - const fn strlen_ct(s: *const c_char) -> usize { |
739 | | - let mut len = 0; |
740 | | - |
741 | | - // SAFETY: Outer caller has provided a pointer to a valid C string. |
742 | | - while unsafe { *s.add(len) } != 0 { |
743 | | - len += 1; |
744 | | - } |
| 737 | + const_eval_select!( |
| 738 | + @capture { s: *const c_char = ptr } -> usize: |
| 739 | + if const { |
| 740 | + let mut len = 0; |
| 741 | + |
| 742 | + // SAFETY: Outer caller has provided a pointer to a valid C string. |
| 743 | + while unsafe { *s.add(len) } != 0 { |
| 744 | + len += 1; |
| 745 | + } |
745 | 746 |
|
746 | | - len |
747 | | - } |
| 747 | + len |
| 748 | + } else { |
| 749 | + extern "C" { |
| 750 | + /// Provided by libc or compiler_builtins. |
| 751 | + fn strlen(s: *const c_char) -> usize; |
| 752 | + } |
748 | 753 |
|
749 | | - #[inline] |
750 | | - fn strlen_rt(s: *const c_char) -> usize { |
751 | | - extern "C" { |
752 | | - /// Provided by libc or compiler_builtins. |
753 | | - fn strlen(s: *const c_char) -> usize; |
| 754 | + // SAFETY: Outer caller has provided a pointer to a valid C string. |
| 755 | + unsafe { strlen(s) } |
754 | 756 | } |
755 | | - |
756 | | - // SAFETY: Outer caller has provided a pointer to a valid C string. |
757 | | - unsafe { strlen(s) } |
758 | | - } |
759 | | - |
760 | | - intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) |
| 757 | + ) |
761 | 758 | } |
762 | 759 |
|
763 | 760 | /// An iterator over the bytes of a [`CStr`], without the nul terminator. |
|
0 commit comments