|
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