@@ -240,7 +240,9 @@ impl CStr {
240240 #[ inline]
241241 #[ must_use]
242242 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
243- pub unsafe fn from_ptr < ' a > ( ptr : * const c_char ) -> & ' a CStr {
243+ #[ rustc_const_unstable( feature = "const_cstr_methods" , issue = "101719" ) ]
244+ #[ rustc_allow_const_fn_unstable( const_eval_select) ]
245+ pub const unsafe fn from_ptr < ' a > ( ptr : * const c_char ) -> & ' a CStr {
244246 // SAFETY: The caller has provided a pointer that points to a valid C
245247 // string with a NUL terminator of size less than `isize::MAX`, whose
246248 // content remain valid and doesn't change for the lifetime of the
@@ -252,13 +254,29 @@ impl CStr {
252254 //
253255 // The cast from c_char to u8 is ok because a c_char is always one byte.
254256 unsafe {
255- extern "C" {
256- /// Provided by libc or compiler_builtins.
257- fn strlen ( s : * const c_char ) -> usize ;
257+ const fn strlen_ct ( s : * const c_char ) -> usize {
258+ let mut len = 0 ;
259+
260+ // SAFETY: Outer caller has provided a pointer to a valid C string.
261+ while unsafe { * s. add ( len) } != 0 {
262+ len += 1 ;
263+ }
264+
265+ len
258266 }
259- let len = strlen ( ptr) ;
260- let ptr = ptr as * const u8 ;
261- CStr :: from_bytes_with_nul_unchecked ( slice:: from_raw_parts ( ptr, len as usize + 1 ) )
267+
268+ fn strlen_rt ( s : * const c_char ) -> usize {
269+ extern "C" {
270+ /// Provided by libc or compiler_builtins.
271+ fn strlen ( s : * const c_char ) -> usize ;
272+ }
273+
274+ // SAFETY: Outer caller has provided a pointer to a valid C string.
275+ unsafe { strlen ( s) }
276+ }
277+
278+ let len = intrinsics:: const_eval_select ( ( ptr, ) , strlen_ct, strlen_rt) ;
279+ Self :: from_bytes_with_nul_unchecked ( slice:: from_raw_parts ( ptr. cast ( ) , len + 1 ) )
262280 }
263281 }
264282
0 commit comments