Skip to content

Commit db43536

Browse files
authored
Rollup merge of rust-lang#102961 - reitermarkus:const-cstr-from-ptr, r=oli-obk
Make `CStr::from_ptr` `const`. Should be included in rust-lang#101719. cc ``@WaffleLapkin``
2 parents cfe440e + b3f9277 commit db43536

File tree

1 file changed

+37
-11
lines changed

1 file changed

+37
-11
lines changed

library/core/src/ffi/c_str.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,7 @@ impl CStr {
221221
/// # Examples
222222
///
223223
/// ```ignore (extern-declaration)
224-
/// # fn main() {
225-
/// use std::ffi::CStr;
226-
/// use std::os::raw::c_char;
224+
/// use std::ffi::{c_char, CStr};
227225
///
228226
/// extern "C" {
229227
/// fn my_string() -> *const c_char;
@@ -233,14 +231,26 @@ impl CStr {
233231
/// let slice = CStr::from_ptr(my_string());
234232
/// println!("string returned: {}", slice.to_str().unwrap());
235233
/// }
236-
/// # }
234+
/// ```
235+
///
236+
/// ```
237+
/// #![feature(const_cstr_methods)]
238+
///
239+
/// use std::ffi::{c_char, CStr};
240+
///
241+
/// const HELLO_PTR: *const c_char = {
242+
/// const BYTES: &[u8] = b"Hello, world!\0";
243+
/// BYTES.as_ptr().cast()
244+
/// };
245+
/// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
237246
/// ```
238247
///
239248
/// [valid]: core::ptr#safety
240249
#[inline]
241250
#[must_use]
242251
#[stable(feature = "rust1", since = "1.0.0")]
243-
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
252+
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
253+
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
244254
// SAFETY: The caller has provided a pointer that points to a valid C
245255
// string with a NUL terminator of size less than `isize::MAX`, whose
246256
// content remain valid and doesn't change for the lifetime of the
@@ -252,13 +262,29 @@ impl CStr {
252262
//
253263
// The cast from c_char to u8 is ok because a c_char is always one byte.
254264
unsafe {
255-
extern "C" {
256-
/// Provided by libc or compiler_builtins.
257-
fn strlen(s: *const c_char) -> usize;
265+
const fn strlen_ct(s: *const c_char) -> usize {
266+
let mut len = 0;
267+
268+
// SAFETY: Outer caller has provided a pointer to a valid C string.
269+
while unsafe { *s.add(len) } != 0 {
270+
len += 1;
271+
}
272+
273+
len
258274
}
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))
275+
276+
fn strlen_rt(s: *const c_char) -> usize {
277+
extern "C" {
278+
/// Provided by libc or compiler_builtins.
279+
fn strlen(s: *const c_char) -> usize;
280+
}
281+
282+
// SAFETY: Outer caller has provided a pointer to a valid C string.
283+
unsafe { strlen(s) }
284+
}
285+
286+
let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
287+
Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
262288
}
263289
}
264290

0 commit comments

Comments
 (0)