@@ -240,7 +240,9 @@ impl CStr {
240
240
#[ inline]
241
241
#[ must_use]
242
242
#[ 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 {
244
246
// SAFETY: The caller has provided a pointer that points to a valid C
245
247
// string with a NUL terminator of size less than `isize::MAX`, whose
246
248
// content remain valid and doesn't change for the lifetime of the
@@ -252,13 +254,29 @@ impl CStr {
252
254
//
253
255
// The cast from c_char to u8 is ok because a c_char is always one byte.
254
256
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
258
266
}
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 ) )
262
280
}
263
281
}
264
282
0 commit comments