about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2022-02-16 19:23:37 +0800
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2022-04-14 21:53:11 +0300
commit5bee741a08a267f68ac6c3d24dadfe927bd45008 (patch)
tree405bb0b23d2fea185c8ef2cfea2a387284c1ba7d
parente7575f9670f3c837def3d186ae09366c75c7632e (diff)
downloadrust-5bee741a08a267f68ac6c3d24dadfe927bd45008.tar.gz
rust-5bee741a08a267f68ac6c3d24dadfe927bd45008.zip
library: Move `CStr` to libcore, and `CString` to liballoc
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_metadata/src/creader.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs24
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs6
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs7
-rw-r--r--library/alloc/src/ffi/c_str.rs (renamed from library/std/src/ffi/c_str.rs)731
-rw-r--r--library/alloc/src/ffi/c_str/tests.rs (renamed from library/std/src/ffi/c_str/tests.rs)32
-rw-r--r--library/alloc/src/ffi/mod.rs91
-rw-r--r--library/alloc/src/lib.rs7
-rw-r--r--library/alloc/src/slice.rs2
-rw-r--r--library/alloc/tests/c_str.rs18
-rw-r--r--library/alloc/tests/lib.rs2
-rw-r--r--library/core/src/ffi/c_str.rs570
-rw-r--r--library/core/src/ffi/mod.rs5
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/error.rs43
-rw-r--r--library/std/src/ffi/mod.rs11
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/prelude/v1.rs4
21 files changed, 916 insertions, 650 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 045fcbac80e..9eba61f8d29 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -731,9 +731,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.70"
+version = "0.1.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80873f979f0a344a4ade87c2f70d9ccf5720b83b10c97ec7cd745895d021e85a"
+checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b8df1632144..9318ebb40b0 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -326,6 +326,8 @@ language_item_table! {
     Range,                   sym::Range,               range_struct,               Target::Struct,         GenericRequirement::None;
     RangeToInclusive,        sym::RangeToInclusive,    range_to_inclusive_struct,  Target::Struct,         GenericRequirement::None;
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
+
+    CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index a9e3b55aeee..566d27212d0 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -417,6 +417,7 @@ impl<'a> CrateLoader<'a> {
 
         let crate_metadata = CrateMetadata::new(
             self.sess,
+            &self.cstore,
             metadata,
             crate_root,
             raw_proc_macros,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3933a0d19a4..8d0e8467404 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1,6 +1,6 @@
 // Decoding metadata from a single crate's metadata
 
-use crate::creader::CrateMetadataRef;
+use crate::creader::{CStore, CrateMetadataRef};
 use crate::rmeta::table::{FixedSizeEncoding, Table};
 use crate::rmeta::*;
 
@@ -1737,6 +1737,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 impl CrateMetadata {
     crate fn new(
         sess: &Session,
+        cstore: &CStore,
         blob: MetadataBlob,
         root: CrateRoot<'static>,
         raw_proc_macros: Option<&'static [ProcMacro]>,
@@ -1752,11 +1753,6 @@ impl CrateMetadata {
             .decode((&blob, sess))
             .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
             .collect();
-        let incoherent_impls = root
-            .incoherent_impls
-            .decode((&blob, sess))
-            .map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls))
-            .collect();
         let alloc_decoding_state =
             AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
         let dependencies = Lock::new(cnum_map.iter().cloned().collect());
@@ -1765,11 +1761,11 @@ impl CrateMetadata {
         // that does not copy any data. It just does some data verification.
         let def_path_hash_map = root.def_path_hash_map.decode(&blob);
 
-        CrateMetadata {
+        let mut cdata = CrateMetadata {
             blob,
             root,
             trait_impls,
-            incoherent_impls,
+            incoherent_impls: Default::default(),
             raw_proc_macros,
             source_map_import_info: OnceCell::new(),
             def_path_hash_map,
@@ -1786,7 +1782,17 @@ impl CrateMetadata {
             hygiene_context: Default::default(),
             def_key_cache: Default::default(),
             def_path_hash_cache: Default::default(),
-        }
+        };
+
+        // Need `CrateMetadataRef` to decode `DefId`s in simplified types.
+        cdata.incoherent_impls = cdata
+            .root
+            .incoherent_impls
+            .decode(CrateMetadataRef { cdata: &cdata, cstore })
+            .map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls))
+            .collect();
+
+        cdata
     }
 
     crate fn dependencies(&self) -> LockGuard<'_, Vec<CrateNum>> {
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 83474bd7e72..e04cc42b6d7 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -644,7 +644,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
             }
             ty::Adt(def, _) => {
-                self.assemble_inherent_impl_candidates_for_type(def.did());
+                let def_id = def.did();
+                self.assemble_inherent_impl_candidates_for_type(def_id);
+                if Some(def_id) == self.tcx.lang_items().c_str() {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
             }
             ty::Foreign(did) => {
                 self.assemble_inherent_impl_candidates_for_type(did);
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index e11bd9355eb..5ad0c4ac52d 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -55,7 +55,12 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
         let self_ty = self.tcx.type_of(item.def_id);
         match *self_ty.kind() {
             ty::Adt(def, _) => {
-                self.check_def_id(item, def.did());
+                let def_id = def.did();
+                if !def_id.is_local() && Some(def_id) == self.tcx.lang_items().c_str() {
+                    self.check_primitive_impl(item.def_id, self_ty, items, ty.span)
+                } else {
+                    self.check_def_id(item, def_id);
+                }
             }
             ty::Foreign(did) => {
                 self.check_def_id(item, did);
diff --git a/library/std/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index a68def1e83d..21433a3baa9 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -1,25 +1,23 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
 #[cfg(test)]
 mod tests;
 
-use crate::ascii;
-use crate::borrow::{Borrow, Cow};
-use crate::cmp::Ordering;
-use crate::error::Error;
-use crate::fmt::{self, Write};
-use crate::io;
-use crate::mem;
-use crate::num::NonZeroU8;
-use crate::ops;
-use crate::os::raw::c_char;
-use crate::ptr;
+use crate::borrow::{Cow, ToOwned};
+use crate::boxed::Box;
 use crate::rc::Rc;
-use crate::slice;
-use crate::str::{self, Utf8Error};
+use crate::slice::hack::into_vec;
+use crate::string::String;
 use crate::sync::Arc;
-use crate::sys;
-use crate::sys_common::memchr;
+use crate::vec::Vec;
+use core::borrow::Borrow;
+use core::ffi::{c_char, CStr};
+use core::fmt;
+use core::mem;
+use core::num::NonZeroU8;
+use core::ops;
+use core::ptr;
+use core::slice;
+use core::slice::memchr;
+use core::str::{self, Utf8Error};
 
 /// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
 /// middle.
@@ -116,90 +114,6 @@ pub struct CString {
     inner: Box<[u8]>,
 }
 
-/// Representation of a borrowed C string.
-///
-/// This type represents a borrowed reference to a nul-terminated
-/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
-/// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
-/// into an owned [`CString`].
-///
-/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
-/// in each pair are borrowed references; the latter are owned
-/// strings.
-///
-/// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
-/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
-/// a safe interface to other consumers.
-///
-/// # Examples
-///
-/// Inspecting a foreign C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// unsafe {
-///     let slice = CStr::from_ptr(my_string());
-///     println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
-/// }
-/// ```
-///
-/// Passing a Rust-originating C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::{CString, CStr};
-/// use std::os::raw::c_char;
-///
-/// fn work(data: &CStr) {
-///     extern "C" { fn work_with(data: *const c_char); }
-///
-///     unsafe { work_with(data.as_ptr()) }
-/// }
-///
-/// let s = CString::new("data data data data").expect("CString::new failed");
-/// work(&s);
-/// ```
-///
-/// Converting a foreign C string into a Rust [`String`]:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// fn my_string_safe() -> String {
-///     unsafe {
-///         CStr::from_ptr(my_string()).to_string_lossy().into_owned()
-///     }
-/// }
-///
-/// println!("string: {}", my_string_safe());
-/// ```
-///
-/// [str]: prim@str "str"
-#[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
-#[stable(feature = "rust1", since = "1.0.0")]
-// FIXME:
-// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
-// on `CStr` being layout-compatible with `[u8]`.
-// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
-// Anyway, `CStr` representation and layout are considered implementation detail, are
-// not documented and must not be relied upon.
-pub struct CStr {
-    // FIXME: this should not be represented with a DST slice but rather with
-    //        just a raw `c_char` along with some form of marker to make
-    //        this an unsized type. Essentially `sizeof(&CStr)` should be the
-    //        same as `sizeof(&c_char)` but `CStr` should be an unsized type.
-    inner: [c_char],
-}
-
 /// An error indicating that an interior nul byte was found.
 ///
 /// While Rust strings may contain nul bytes in the middle, C strings
@@ -219,25 +133,10 @@ pub struct CStr {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct NulError(usize, Vec<u8>);
 
-/// An error indicating that a nul byte was not in the expected position.
-///
-/// The slice used to create a [`CStr`] must have one and only one nul byte,
-/// positioned at the end.
-///
-/// This error is created by the [`CStr::from_bytes_with_nul`] method.
-/// See its documentation for more.
-///
-/// # Examples
-///
-/// ```
-/// use std::ffi::{CStr, FromBytesWithNulError};
-///
-/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
-/// ```
 #[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub struct FromBytesWithNulError {
-    kind: FromBytesWithNulErrorKind,
+enum FromBytesWithNulErrorKind {
+    InteriorNul(usize),
+    NotNulTerminated,
 }
 
 /// An error indicating that a nul byte was not in the expected position.
@@ -262,21 +161,6 @@ pub struct FromVecWithNulError {
     bytes: Vec<u8>,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum FromBytesWithNulErrorKind {
-    InteriorNul(usize),
-    NotNulTerminated,
-}
-
-impl FromBytesWithNulError {
-    fn interior_nul(pos: usize) -> FromBytesWithNulError {
-        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
-    }
-    fn not_nul_terminated() -> FromBytesWithNulError {
-        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
-    }
-}
-
 #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl FromVecWithNulError {
     /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
@@ -328,27 +212,6 @@ impl FromVecWithNulError {
     }
 }
 
-/// An error indicating that no nul byte was present.
-///
-/// A slice used to create a [`CStr`] must contain a nul byte somewhere
-/// within the slice.
-///
-/// This error is created by the [`CStr::from_bytes_until_nul`] method.
-///
-#[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-pub struct FromBytesUntilNulError(());
-
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-impl Error for FromBytesUntilNulError {}
-
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-impl fmt::Display for FromBytesUntilNulError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "data provided does not contain a nul")
-    }
-}
-
 /// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
 ///
 /// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
@@ -536,7 +399,11 @@ impl CString {
         // information about the size of the allocation is correct on Rust's
         // side.
         unsafe {
-            let len = sys::strlen(ptr) + 1; // Including the NUL byte
+            extern "C" {
+                /// Provided by libc or compiler_builtins.
+                fn strlen(s: *const c_char) -> usize;
+            }
+            let len = strlen(ptr) + 1; // Including the NUL byte
             let slice = slice::from_raw_parts_mut(ptr, len as usize);
             CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
         }
@@ -626,7 +493,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes(self) -> Vec<u8> {
-        let mut vec = self.into_inner().into_vec();
+        let mut vec = into_vec(self.into_inner());
         let _nul = vec.pop();
         debug_assert_eq!(_nul, Some(0u8));
         vec
@@ -647,7 +514,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes_with_nul(self) -> Vec<u8> {
-        self.into_inner().into_vec()
+        into_vec(self.into_inner())
     }
 
     /// Returns the contents of this `CString` as a slice of bytes.
@@ -842,7 +709,7 @@ impl ops::Deref for CString {
 
     #[inline]
     fn deref(&self) -> &CStr {
-        unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
     }
 }
 
@@ -864,25 +731,6 @@ impl From<CString> for Vec<u8> {
     }
 }
 
-#[stable(feature = "cstr_debug", since = "1.3.0")]
-impl fmt::Debug for CStr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "\"")?;
-        for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
-            f.write_char(byte as char)?;
-        }
-        write!(f, "\"")
-    }
-}
-
-#[stable(feature = "cstr_default", since = "1.10.0")]
-impl Default for &CStr {
-    fn default() -> Self {
-        const SLICE: &[c_char] = &[0];
-        unsafe { CStr::from_ptr(SLICE.as_ptr()) }
-    }
-}
-
 #[stable(feature = "cstr_default", since = "1.10.0")]
 impl Default for CString {
     /// Creates an empty `CString`.
@@ -910,6 +758,7 @@ impl<'a> From<Cow<'a, CStr>> for CString {
     }
 }
 
+#[cfg(not(test))]
 #[stable(feature = "box_from_c_str", since = "1.17.0")]
 impl From<&CStr> for Box<CStr> {
     /// Converts a `&CStr` into a `Box<CStr>`,
@@ -938,7 +787,8 @@ impl From<Box<CStr>> for CString {
     /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
     #[inline]
     fn from(s: Box<CStr>) -> CString {
-        s.into_c_string()
+        let raw = Box::into_raw(s) as *mut [u8];
+        CString { inner: unsafe { Box::from_raw(raw) } }
     }
 }
 
@@ -964,6 +814,7 @@ impl From<Vec<NonZeroU8>> for CString {
     }
 }
 
+#[cfg(not(test))]
 #[stable(feature = "more_box_slice_clone", since = "1.29.0")]
 impl Clone for Box<CStr> {
     #[inline]
@@ -1052,6 +903,7 @@ impl From<&CStr> for Rc<CStr> {
     }
 }
 
+#[cfg(not(test))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
     fn default() -> Box<CStr> {
@@ -1100,56 +952,12 @@ impl NulError {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Error for NulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "nul byte found in data"
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for NulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "nul byte found in provided data at position: {}", self.0)
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From<NulError> for io::Error {
-    /// Converts a [`NulError`] into a [`io::Error`].
-    fn from(_: NulError) -> io::Error {
-        io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
-    }
-}
-
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl Error for FromBytesWithNulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        match self.kind {
-            FromBytesWithNulErrorKind::InteriorNul(..) => {
-                "data provided contains an interior nul byte"
-            }
-            FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
-        }
-    }
-}
-
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl fmt::Display for FromBytesWithNulError {
-    #[allow(deprecated, deprecated_in_future)]
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(self.description())?;
-        if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
-            write!(f, " at byte pos {pos}")?;
-        }
-        Ok(())
-    }
-}
-
-#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
-impl Error for FromVecWithNulError {}
-
 #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl fmt::Display for FromVecWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1179,18 +987,18 @@ impl IntoStringError {
     pub fn utf8_error(&self) -> Utf8Error {
         self.error
     }
+
+    #[doc(hidden)]
+    #[unstable(feature = "cstr_internals", issue = "none")]
+    pub fn __source(&self) -> &Utf8Error {
+        &self.error
+    }
 }
 
-#[stable(feature = "cstring_into", since = "1.7.0")]
-impl Error for IntoStringError {
-    #[allow(deprecated)]
+impl IntoStringError {
     fn description(&self) -> &str {
         "C string contained non-utf8 bytes"
     }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Some(&self.error)
-    }
 }
 
 #[stable(feature = "cstring_into", since = "1.7.0")]
@@ -1201,327 +1009,126 @@ impl fmt::Display for IntoStringError {
     }
 }
 
-impl CStr {
-    /// Wraps a raw C string with a safe C string wrapper.
-    ///
-    /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
-    /// allows inspection and interoperation of non-owned C strings. The total
-    /// size of the raw C string must be smaller than `isize::MAX` **bytes**
-    /// in memory due to calling the `slice::from_raw_parts` function.
-    /// This method is unsafe for a number of reasons:
-    ///
-    /// * There is no guarantee to the validity of `ptr`.
-    /// * The returned lifetime is not guaranteed to be the actual lifetime of
-    ///   `ptr`.
-    /// * There is no guarantee that the memory pointed to by `ptr` contains a
-    ///   valid nul terminator byte at the end of the string.
-    /// * It is not guaranteed that the memory pointed by `ptr` won't change
-    ///   before the `CStr` has been destroyed.
-    ///
-    /// > **Note**: This operation is intended to be a 0-cost cast but it is
-    /// > currently implemented with an up-front calculation of the length of
-    /// > the string. This is not guaranteed to always be the case.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore (extern-declaration)
-    /// # fn main() {
-    /// use std::ffi::CStr;
-    /// use std::os::raw::c_char;
-    ///
-    /// extern "C" {
-    ///     fn my_string() -> *const c_char;
-    /// }
-    ///
-    /// unsafe {
-    ///     let slice = CStr::from_ptr(my_string());
-    ///     println!("string returned: {}", slice.to_str().unwrap());
-    /// }
-    /// # }
-    /// ```
-    #[inline]
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
-        // SAFETY: The caller has provided a pointer that points to a valid C
-        // string with a NUL terminator of size less than `isize::MAX`, whose
-        // content remain valid and doesn't change for the lifetime of the
-        // returned `CStr`.
-        //
-        // Thus computing the length is fine (a NUL byte exists), the call to
-        // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
-        // the call to `from_bytes_with_nul_unchecked` is correct.
-        //
-        // The cast from c_char to u8 is ok because a c_char is always one byte.
-        unsafe {
-            let len = sys::strlen(ptr);
-            let ptr = ptr as *const u8;
-            Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
-        }
-    }
+#[stable(feature = "cstr_borrow", since = "1.3.0")]
+impl ToOwned for CStr {
+    type Owned = CString;
 
-    /// Creates a C string wrapper from a byte slice.
-    ///
-    /// This method will create a `CStr` from any byte slice that contains at
-    /// least one nul byte. The caller does not need to know or specify where
-    /// the nul byte is located.
-    ///
-    /// If the first byte is a nul character, this method will return an
-    /// empty `CStr`. If multiple nul characters are present, the `CStr` will
-    /// end at the first one.
-    ///
-    /// If the slice only has a single nul byte at the end, this method is
-    /// equivalent to [`CStr::from_bytes_with_nul`].
-    ///
-    /// # Examples
-    /// ```
-    /// #![feature(cstr_from_bytes_until_nul)]
-    ///
-    /// use std::ffi::CStr;
-    ///
-    /// let mut buffer = [0u8; 16];
-    /// unsafe {
-    ///     // Here we might call an unsafe C function that writes a string
-    ///     // into the buffer.
-    ///     let buf_ptr = buffer.as_mut_ptr();
-    ///     buf_ptr.write_bytes(b'A', 8);
-    /// }
-    /// // Attempt to extract a C nul-terminated string from the buffer.
-    /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
-    /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
-    /// ```
-    ///
-    #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-    pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
-        let nul_pos = memchr::memchr(0, bytes);
-        match nul_pos {
-            Some(nul_pos) => {
-                // SAFETY: We know there is a nul byte at nul_pos, so this slice
-                // (ending at the nul byte) is a well-formed C string.
-                let subslice = &bytes[..nul_pos + 1];
-                Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
-            }
-            None => Err(FromBytesUntilNulError(())),
-        }
+    fn to_owned(&self) -> CString {
+        CString { inner: self.to_bytes_with_nul().into() }
     }
 
-    /// Creates a C string wrapper from a byte slice.
-    ///
-    /// This function will cast the provided `bytes` to a `CStr`
-    /// wrapper after ensuring that the byte slice is nul-terminated
-    /// and does not contain any interior nul bytes.
-    ///
-    /// If the nul byte may not be at the end,
-    /// [`CStr::from_bytes_until_nul`] can be used instead.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::ffi::CStr;
-    ///
-    /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
-    /// assert!(cstr.is_ok());
-    /// ```
-    ///
-    /// Creating a `CStr` without a trailing nul terminator is an error:
-    ///
-    /// ```
-    /// use std::ffi::CStr;
-    ///
-    /// let cstr = CStr::from_bytes_with_nul(b"hello");
-    /// assert!(cstr.is_err());
-    /// ```
-    ///
-    /// Creating a `CStr` with an interior nul byte is an error:
-    ///
-    /// ```
-    /// use std::ffi::CStr;
-    ///
-    /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
-    /// assert!(cstr.is_err());
-    /// ```
-    #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
-        let nul_pos = memchr::memchr(0, bytes);
-        match nul_pos {
-            Some(nul_pos) if nul_pos + 1 == bytes.len() => {
-                // SAFETY: We know there is only one nul byte, at the end
-                // of the byte slice.
-                Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) })
-            }
-            Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
-            None => Err(FromBytesWithNulError::not_nul_terminated()),
-        }
+    fn clone_into(&self, target: &mut CString) {
+        let mut b = into_vec(mem::take(&mut target.inner));
+        self.to_bytes_with_nul().clone_into(&mut b);
+        target.inner = b.into_boxed_slice();
     }
+}
 
-    /// Unsafely creates a C string wrapper from a byte slice.
-    ///
-    /// This function will cast the provided `bytes` to a `CStr` wrapper without
-    /// performing any sanity checks. The provided slice **must** be nul-terminated
-    /// and not contain any interior nul bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::ffi::{CStr, CString};
-    ///
-    /// unsafe {
-    ///     let cstring = CString::new("hello").expect("CString::new failed");
-    ///     let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
-    ///     assert_eq!(cstr, &*cstring);
-    /// }
-    /// ```
-    #[inline]
-    #[must_use]
-    #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
-    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
-        // We're in a const fn, so this is the best we can do
-        debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
-        unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl From<&CStr> for CString {
+    fn from(s: &CStr) -> CString {
+        s.to_owned()
     }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl ops::Index<ops::RangeFull> for CString {
+    type Output = CStr;
 
     #[inline]
-    const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
-        // SAFETY: Casting to CStr is safe because its internal representation
-        // is a [u8] too (safe only inside std).
-        // Dereferencing the obtained pointer is safe because it comes from a
-        // reference. Making a reference is then safe because its lifetime
-        // is bound by the lifetime of the given `bytes`.
-        unsafe { &*(bytes as *const [u8] as *const Self) }
+    fn index(&self, _index: ops::RangeFull) -> &CStr {
+        self
     }
+}
 
-    /// Returns the inner pointer to this C string.
-    ///
-    /// The returned pointer will be valid for as long as `self` is, and points
-    /// to a contiguous region of memory terminated with a 0 byte to represent
-    /// the end of the string.
-    ///
-    /// **WARNING**
-    ///
-    /// The returned pointer is read-only; writing to it (including passing it
-    /// to C code that writes to it) causes undefined behavior.
-    ///
-    /// It is your responsibility to make sure that the underlying memory is not
-    /// freed too early. For example, the following code will cause undefined
-    /// behavior when `ptr` is used inside the `unsafe` block:
-    ///
-    /// ```no_run
-    /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
-    /// use std::ffi::CString;
-    ///
-    /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
-    /// unsafe {
-    ///     // `ptr` is dangling
-    ///     *ptr;
-    /// }
-    /// ```
-    ///
-    /// This happens because the pointer returned by `as_ptr` does not carry any
-    /// lifetime information and the [`CString`] is deallocated immediately after
-    /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
-    /// expression is evaluated.
-    /// To fix the problem, bind the `CString` to a local variable:
-    ///
-    /// ```no_run
-    /// # #![allow(unused_must_use)]
-    /// use std::ffi::CString;
-    ///
-    /// let hello = CString::new("Hello").expect("CString::new failed");
-    /// let ptr = hello.as_ptr();
-    /// unsafe {
-    ///     // `ptr` is valid because `hello` is in scope
-    ///     *ptr;
-    /// }
-    /// ```
-    ///
-    /// This way, the lifetime of the [`CString`] in `hello` encompasses
-    /// the lifetime of `ptr` and the `unsafe` block.
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef<CStr> for CString {
     #[inline]
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
-    pub const fn as_ptr(&self) -> *const c_char {
-        self.inner.as_ptr()
+    fn as_ref(&self) -> &CStr {
+        self
     }
+}
 
-    /// Converts this C string to a byte slice.
+#[cfg(bootstrap)]
+#[doc(hidden)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub trait CStrExt {
+    /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
     ///
-    /// The returned slice will **not** contain the trailing nul terminator that this C
-    /// string has.
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return a <code>[Cow]::[Borrowed]\(&[str])</code>
+    /// with the corresponding <code>&[str]</code> slice. Otherwise, it will
+    /// replace any invalid UTF-8 sequences with
+    /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
+    /// <code>[Cow]::[Owned]\(&[str])</code> with the result.
     ///
-    /// > **Note**: This method is currently implemented as a constant-time
-    /// > cast, but it is planned to alter its definition in the future to
-    /// > perform the length calculation whenever this method is called.
+    /// [str]: prim@str "str"
+    /// [Borrowed]: Cow::Borrowed
+    /// [Owned]: Cow::Owned
+    /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
     ///
     /// # Examples
     ///
+    /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+    ///
     /// ```
+    /// use std::borrow::Cow;
     /// use std::ffi::CStr;
     ///
-    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
-    /// assert_eq!(cstr.to_bytes(), b"foo");
+    /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
+    ///                  .expect("CStr::from_bytes_with_nul failed");
+    /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
     /// ```
-    #[inline]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn to_bytes(&self) -> &[u8] {
-        let bytes = self.to_bytes_with_nul();
-        // SAFETY: to_bytes_with_nul returns slice with length at least 1
-        unsafe { bytes.get_unchecked(..bytes.len() - 1) }
-    }
-
-    /// Converts this C string to a byte slice containing the trailing 0 byte.
-    ///
-    /// This function is the equivalent of [`CStr::to_bytes`] except that it
-    /// will retain the trailing nul terminator instead of chopping it off.
     ///
-    /// > **Note**: This method is currently implemented as a 0-cost cast, but
-    /// > it is planned to alter its definition in the future to perform the
-    /// > length calculation whenever this method is called.
-    ///
-    /// # Examples
+    /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
     ///
     /// ```
+    /// use std::borrow::Cow;
     /// use std::ffi::CStr;
     ///
-    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
-    /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
+    /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
+    ///                  .expect("CStr::from_bytes_with_nul failed");
+    /// assert_eq!(
+    ///     cstr.to_string_lossy(),
+    ///     Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
+    /// );
     /// ```
-    #[inline]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn to_bytes_with_nul(&self) -> &[u8] {
-        unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
-    }
+    #[stable(feature = "cstr_to_str", since = "1.4.0")]
+    fn to_string_lossy(&self) -> Cow<'_, str>;
 
-    /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
-    ///
-    /// If the contents of the `CStr` are valid UTF-8 data, this
-    /// function will return the corresponding <code>&[str]</code> slice. Otherwise,
-    /// it will return an error with details of where UTF-8 validation failed.
-    ///
-    /// [str]: prim@str "str"
+    /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
     ///
     /// # Examples
     ///
     /// ```
-    /// use std::ffi::CStr;
+    /// use std::ffi::CString;
     ///
-    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
-    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
+    /// let boxed = c_string.into_boxed_c_str();
+    /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
     /// ```
-    #[stable(feature = "cstr_to_str", since = "1.4.0")]
-    pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
-        // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
-        // instead of in `from_ptr()`, it may be worth considering if this should
-        // be rewritten to do the UTF-8 check inline with the length calculation
-        // instead of doing it afterwards.
-        str::from_utf8(self.to_bytes())
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+    fn into_c_string(self: Box<Self>) -> CString;
+}
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+impl CStrExt for CStr {
+    fn to_string_lossy(&self) -> Cow<'_, str> {
+        String::from_utf8_lossy(self.to_bytes())
     }
 
+    fn into_c_string(self: Box<Self>) -> CString {
+        CString::from(self)
+    }
+}
+
+#[cfg(not(bootstrap))]
+#[cfg(not(test))]
+impl CStr {
     /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
     ///
     /// If the contents of the `CStr` are valid UTF-8 data, this
@@ -1534,7 +1141,7 @@ impl CStr {
     /// [str]: prim@str "str"
     /// [Borrowed]: Cow::Borrowed
     /// [Owned]: Cow::Owned
-    /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
+    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
     ///
     /// # Examples
     ///
@@ -1562,6 +1169,7 @@ impl CStr {
     ///     Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
     /// );
     /// ```
+    #[rustc_allow_incoherent_impl]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
     #[stable(feature = "cstr_to_str", since = "1.4.0")]
@@ -1580,101 +1188,10 @@ impl CStr {
     /// let boxed = c_string.into_boxed_c_str();
     /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
     /// ```
+    #[rustc_allow_incoherent_impl]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
-    pub fn into_c_string(self: Box<CStr>) -> CString {
-        let raw = Box::into_raw(self) as *mut [u8];
-        CString { inner: unsafe { Box::from_raw(raw) } }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialEq for CStr {
-    fn eq(&self, other: &CStr) -> bool {
-        self.to_bytes().eq(other.to_bytes())
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Eq for CStr {}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for CStr {
-    fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
-        self.to_bytes().partial_cmp(&other.to_bytes())
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for CStr {
-    fn cmp(&self, other: &CStr) -> Ordering {
-        self.to_bytes().cmp(&other.to_bytes())
-    }
-}
-
-#[stable(feature = "cstr_borrow", since = "1.3.0")]
-impl ToOwned for CStr {
-    type Owned = CString;
-
-    fn to_owned(&self) -> CString {
-        CString { inner: self.to_bytes_with_nul().into() }
-    }
-
-    fn clone_into(&self, target: &mut CString) {
-        let mut b = Vec::from(mem::take(&mut target.inner));
-        self.to_bytes_with_nul().clone_into(&mut b);
-        target.inner = b.into_boxed_slice();
-    }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl From<&CStr> for CString {
-    /// Copies the contents of the `&CStr` into a newly allocated `CString`.
-    fn from(s: &CStr) -> CString {
-        s.to_owned()
-    }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl ops::Index<ops::RangeFull> for CString {
-    type Output = CStr;
-
-    #[inline]
-    fn index(&self, _index: ops::RangeFull) -> &CStr {
-        self
-    }
-}
-
-#[stable(feature = "cstr_range_from", since = "1.47.0")]
-impl ops::Index<ops::RangeFrom<usize>> for CStr {
-    type Output = CStr;
-
-    fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
-        let bytes = self.to_bytes_with_nul();
-        // we need to manually check the starting index to account for the null
-        // byte, since otherwise we could get an empty string that doesn't end
-        // in a null.
-        if index.start < bytes.len() {
-            unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) }
-        } else {
-            panic!(
-                "index out of bounds: the len is {} but the index is {}",
-                bytes.len(),
-                index.start
-            );
-        }
-    }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl AsRef<CStr> for CStr {
-    #[inline]
-    fn as_ref(&self) -> &CStr {
-        self
-    }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl AsRef<CStr> for CString {
-    #[inline]
-    fn as_ref(&self) -> &CStr {
-        self
+    pub fn into_c_string(self: Box<Self>) -> CString {
+        CString::from(self)
     }
 }
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/alloc/src/ffi/c_str/tests.rs
index c20da138a18..0b7476d5cc7 100644
--- a/library/std/src/ffi/c_str/tests.rs
+++ b/library/alloc/src/ffi/c_str/tests.rs
@@ -1,10 +1,12 @@
 use super::*;
-use crate::borrow::Cow::{Borrowed, Owned};
-use crate::collections::hash_map::DefaultHasher;
-use crate::hash::{Hash, Hasher};
-use crate::os::raw::c_char;
 use crate::rc::Rc;
 use crate::sync::Arc;
+use core::assert_matches::assert_matches;
+use core::ffi::FromBytesUntilNulError;
+use core::hash::{Hash, Hasher};
+
+#[allow(deprecated)]
+use core::hash::SipHasher13 as DefaultHasher;
 
 #[test]
 fn c_to_rust() {
@@ -48,22 +50,6 @@ fn borrowed() {
 }
 
 #[test]
-fn to_str() {
-    let data = b"123\xE2\x80\xA6\0";
-    let ptr = data.as_ptr() as *const c_char;
-    unsafe {
-        assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
-        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
-    }
-    let data = b"123\xE2\0";
-    let ptr = data.as_ptr() as *const c_char;
-    unsafe {
-        assert!(CStr::from_ptr(ptr).to_str().is_err());
-        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
-    }
-}
-
-#[test]
 fn to_owned() {
     let data = b"123\0";
     let ptr = data.as_ptr() as *const c_char;
@@ -78,9 +64,11 @@ fn equal_hash() {
     let ptr = data.as_ptr() as *const c_char;
     let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
 
+    #[allow(deprecated)]
     let mut s = DefaultHasher::new();
     cstr.hash(&mut s);
     let cstr_hash = s.finish();
+    #[allow(deprecated)]
     let mut s = DefaultHasher::new();
     CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
     let cstring_hash = s.finish();
@@ -122,11 +110,11 @@ fn cstr_from_bytes_until_nul() {
     // Test an empty slice. This should fail because it
     // does not contain a nul byte.
     let b = b"";
-    assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+    assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. }));
 
     // Test a non-empty slice, that does not contain a nul byte.
     let b = b"hello";
-    assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+    assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. }));
 
     // Test an empty nul-terminated string
     let b = b"\0";
diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs
new file mode 100644
index 00000000000..6b2e4af45b2
--- /dev/null
+++ b/library/alloc/src/ffi/mod.rs
@@ -0,0 +1,91 @@
+//! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e., if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e., they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is an *O*(1) operation (because the
+//! length is stored); in C it is an *O*(*n*) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a [`CString`] out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw <code>\*mut [u8]</code> that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw <code>\*const [u8]</code> that you got from
+//! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a [`CStr`], you can convert it to a Rust
+//! <code>&[str]</code> if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`String`]: crate::string::String
+//! [`CStr`]: core::ffi::CStr
+
+#![unstable(feature = "alloc_ffi", issue = "94079")]
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub use self::c_str::CStrExt;
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+pub use self::c_str::FromVecWithNulError;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::c_str::{CString, IntoStringError, NulError};
+
+mod c_str;
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index c54001dceea..f577afdce1e 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -91,6 +91,7 @@
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_windows)]
+#![feature(assert_matches)]
 #![feature(async_iterator)]
 #![feature(coerce_unsized)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
@@ -105,8 +106,10 @@
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_refs_to_cell)]
 #![feature(core_intrinsics)]
+#![feature(core_ffi_c)]
 #![feature(const_eval_select)]
 #![feature(const_pin)]
+#![feature(cstr_from_bytes_until_nul)]
 #![feature(dispatch_from_dyn)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
@@ -152,6 +155,7 @@
 #![feature(exclusive_range_pattern)]
 #![feature(fundamental)]
 #![cfg_attr(not(test), feature(generator_trait))]
+#![feature(hashmap_internals)]
 #![feature(lang_items)]
 #![feature(let_else)]
 #![feature(min_specialization)]
@@ -160,6 +164,7 @@
 #![feature(nll)] // Not necessary, but here to test the `nll` feature.
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
+#![feature(slice_internals)]
 #![feature(staged_api)]
 #![cfg_attr(test, feature(test))]
 #![feature(unboxed_closures)]
@@ -205,6 +210,8 @@ mod boxed {
 }
 pub mod borrow;
 pub mod collections;
+#[cfg(not(no_global_oom_handling))]
+pub mod ffi;
 pub mod fmt;
 pub mod rc;
 pub mod slice;
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 31edbe0c5af..02a47c57b8a 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -153,7 +153,7 @@ pub use hack::to_vec;
 // functions are actually methods that are in `impl [T]` but not in
 // `core::slice::SliceExt` - we need to supply these functions for the
 // `test_permutations` test
-mod hack {
+pub(crate) mod hack {
     use core::alloc::Allocator;
 
     use crate::boxed::Box;
diff --git a/library/alloc/tests/c_str.rs b/library/alloc/tests/c_str.rs
new file mode 100644
index 00000000000..8fbb10e1d5c
--- /dev/null
+++ b/library/alloc/tests/c_str.rs
@@ -0,0 +1,18 @@
+use std::borrow::Cow::{Borrowed, Owned};
+use std::ffi::{c_char, CStr};
+
+#[test]
+fn to_str() {
+    let data = b"123\xE2\x80\xA6\0";
+    let ptr = data.as_ptr() as *const c_char;
+    unsafe {
+        assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+    }
+    let data = b"123\xE2\0";
+    let ptr = data.as_ptr() as *const c_char;
+    unsafe {
+        assert!(CStr::from_ptr(ptr).to_str().is_err());
+        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
+    }
+}
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 16d3b368595..11cd998c957 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -12,6 +12,7 @@
 #![feature(const_nonnull_slice_from_raw_parts)]
 #![feature(const_ptr_write)]
 #![feature(const_try)]
+#![feature(core_ffi_c)]
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
@@ -49,6 +50,7 @@ mod binary_heap;
 mod borrow;
 mod boxed;
 mod btree_set_hash;
+mod c_str;
 mod const_fns;
 mod cow_str;
 mod fmt;
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
new file mode 100644
index 00000000000..005db8d6883
--- /dev/null
+++ b/library/core/src/ffi/c_str.rs
@@ -0,0 +1,570 @@
+use crate::ascii;
+use crate::cmp::Ordering;
+use crate::ffi::c_char;
+use crate::fmt::{self, Write};
+use crate::ops;
+use crate::slice;
+use crate::slice::memchr;
+use crate::str;
+
+/// Representation of a borrowed C string.
+///
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
+/// into an owned `CString`.
+///
+/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
+///
+/// Note that this structure is **not** `repr(C)` and is not recommended to be
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
+/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
+/// a safe interface to other consumers.
+///
+/// # Examples
+///
+/// Inspecting a foreign C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern "C" { fn my_string() -> *const c_char; }
+///
+/// unsafe {
+///     let slice = CStr::from_ptr(my_string());
+///     println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
+/// }
+/// ```
+///
+/// Passing a Rust-originating C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::{CString, CStr};
+/// use std::os::raw::c_char;
+///
+/// fn work(data: &CStr) {
+///     extern "C" { fn work_with(data: *const c_char); }
+///
+///     unsafe { work_with(data.as_ptr()) }
+/// }
+///
+/// let s = CString::new("data data data data").expect("CString::new failed");
+/// work(&s);
+/// ```
+///
+/// Converting a foreign C string into a Rust `String`:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern "C" { fn my_string() -> *const c_char; }
+///
+/// fn my_string_safe() -> String {
+///     unsafe {
+///         CStr::from_ptr(my_string()).to_string_lossy().into_owned()
+///     }
+/// }
+///
+/// println!("string: {}", my_string_safe());
+/// ```
+///
+/// [str]: prim@str "str"
+#[derive(Hash)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
+// FIXME:
+// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
+// on `CStr` being layout-compatible with `[u8]`.
+// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
+// Anyway, `CStr` representation and layout are considered implementation detail, are
+// not documented and must not be relied upon.
+pub struct CStr {
+    // FIXME: this should not be represented with a DST slice but rather with
+    //        just a raw `c_char` along with some form of marker to make
+    //        this an unsized type. Essentially `sizeof(&CStr)` should be the
+    //        same as `sizeof(&c_char)` but `CStr` should be an unsized type.
+    inner: [c_char],
+}
+
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul byte,
+/// positioned at the end.
+///
+/// This error is created by the [`CStr::from_bytes_with_nul`] method.
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CStr, FromBytesWithNulError};
+///
+/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub struct FromBytesWithNulError {
+    kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+    InteriorNul(usize),
+    NotNulTerminated,
+}
+
+impl FromBytesWithNulError {
+    fn interior_nul(pos: usize) -> FromBytesWithNulError {
+        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
+    }
+    fn not_nul_terminated() -> FromBytesWithNulError {
+        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "cstr_internals", issue = "none")]
+    pub fn __description(&self) -> &str {
+        match self.kind {
+            FromBytesWithNulErrorKind::InteriorNul(..) => {
+                "data provided contains an interior nul byte"
+            }
+            FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
+        }
+    }
+}
+
+/// An error indicating that no nul byte was present.
+///
+/// A slice used to create a [`CStr`] must contain a nul byte somewhere
+/// within the slice.
+///
+/// This error is created by the [`CStr::from_bytes_until_nul`] method.
+///
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+pub struct FromBytesUntilNulError(());
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl fmt::Display for FromBytesUntilNulError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "data provided does not contain a nul")
+    }
+}
+
+#[stable(feature = "cstr_debug", since = "1.3.0")]
+impl fmt::Debug for CStr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "\"")?;
+        for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
+            f.write_char(byte as char)?;
+        }
+        write!(f, "\"")
+    }
+}
+
+#[stable(feature = "cstr_default", since = "1.10.0")]
+impl Default for &CStr {
+    fn default() -> Self {
+        const SLICE: &[c_char] = &[0];
+        // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string.
+        unsafe { CStr::from_ptr(SLICE.as_ptr()) }
+    }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl fmt::Display for FromBytesWithNulError {
+    #[allow(deprecated, deprecated_in_future)]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(self.__description())?;
+        if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+            write!(f, " at byte pos {pos}")?;
+        }
+        Ok(())
+    }
+}
+
+impl CStr {
+    /// Wraps a raw C string with a safe C string wrapper.
+    ///
+    /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
+    /// allows inspection and interoperation of non-owned C strings. The total
+    /// size of the raw C string must be smaller than `isize::MAX` **bytes**
+    /// in memory due to calling the `slice::from_raw_parts` function.
+    /// This method is unsafe for a number of reasons:
+    ///
+    /// * There is no guarantee to the validity of `ptr`.
+    /// * The returned lifetime is not guaranteed to be the actual lifetime of
+    ///   `ptr`.
+    /// * There is no guarantee that the memory pointed to by `ptr` contains a
+    ///   valid nul terminator byte at the end of the string.
+    /// * It is not guaranteed that the memory pointed by `ptr` won't change
+    ///   before the `CStr` has been destroyed.
+    ///
+    /// > **Note**: This operation is intended to be a 0-cost cast but it is
+    /// > currently implemented with an up-front calculation of the length of
+    /// > the string. This is not guaranteed to always be the case.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// # fn main() {
+    /// use std::ffi::CStr;
+    /// use std::os::raw::c_char;
+    ///
+    /// extern "C" {
+    ///     fn my_string() -> *const c_char;
+    /// }
+    ///
+    /// unsafe {
+    ///     let slice = CStr::from_ptr(my_string());
+    ///     println!("string returned: {}", slice.to_str().unwrap());
+    /// }
+    /// # }
+    /// ```
+    #[inline]
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+        // SAFETY: The caller has provided a pointer that points to a valid C
+        // string with a NUL terminator of size less than `isize::MAX`, whose
+        // content remain valid and doesn't change for the lifetime of the
+        // returned `CStr`.
+        //
+        // Thus computing the length is fine (a NUL byte exists), the call to
+        // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
+        // the call to `from_bytes_with_nul_unchecked` is correct.
+        //
+        // The cast from c_char to u8 is ok because a c_char is always one byte.
+        unsafe {
+            extern "C" {
+                /// Provided by libc or compiler_builtins.
+                fn strlen(s: *const c_char) -> usize;
+            }
+            let len = strlen(ptr);
+            let ptr = ptr as *const u8;
+            CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+        }
+    }
+
+    /// Creates a C string wrapper from a byte slice.
+    ///
+    /// This method will create a `CStr` from any byte slice that contains at
+    /// least one nul byte. The caller does not need to know or specify where
+    /// the nul byte is located.
+    ///
+    /// If the first byte is a nul character, this method will return an
+    /// empty `CStr`. If multiple nul characters are present, the `CStr` will
+    /// end at the first one.
+    ///
+    /// If the slice only has a single nul byte at the end, this method is
+    /// equivalent to [`CStr::from_bytes_with_nul`].
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(cstr_from_bytes_until_nul)]
+    ///
+    /// use std::ffi::CStr;
+    ///
+    /// let mut buffer = [0u8; 16];
+    /// unsafe {
+    ///     // Here we might call an unsafe C function that writes a string
+    ///     // into the buffer.
+    ///     let buf_ptr = buffer.as_mut_ptr();
+    ///     buf_ptr.write_bytes(b'A', 8);
+    /// }
+    /// // Attempt to extract a C nul-terminated string from the buffer.
+    /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
+    /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
+    /// ```
+    ///
+    #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+    pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
+        let nul_pos = memchr::memchr(0, bytes);
+        match nul_pos {
+            Some(nul_pos) => {
+                let subslice = &bytes[..nul_pos + 1];
+                // SAFETY: We know there is a nul byte at nul_pos, so this slice
+                // (ending at the nul byte) is a well-formed C string.
+                Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
+            }
+            None => Err(FromBytesUntilNulError(())),
+        }
+    }
+
+    /// Creates a C string wrapper from a byte slice.
+    ///
+    /// This function will cast the provided `bytes` to a `CStr`
+    /// wrapper after ensuring that the byte slice is nul-terminated
+    /// and does not contain any interior nul bytes.
+    ///
+    /// If the nul byte may not be at the end,
+    /// [`CStr::from_bytes_until_nul`] can be used instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
+    /// assert!(cstr.is_ok());
+    /// ```
+    ///
+    /// Creating a `CStr` without a trailing nul terminator is an error:
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"hello");
+    /// assert!(cstr.is_err());
+    /// ```
+    ///
+    /// Creating a `CStr` with an interior nul byte is an error:
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
+    /// assert!(cstr.is_err());
+    /// ```
+    #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
+        let nul_pos = memchr::memchr(0, bytes);
+        match nul_pos {
+            Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+                // SAFETY: We know there is only one nul byte, at the end
+                // of the byte slice.
+                Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+            }
+            Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+            None => Err(FromBytesWithNulError::not_nul_terminated()),
+        }
+    }
+
+    /// Unsafely creates a C string wrapper from a byte slice.
+    ///
+    /// This function will cast the provided `bytes` to a `CStr` wrapper without
+    /// performing any sanity checks. The provided slice **must** be nul-terminated
+    /// and not contain any interior nul bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::{CStr, CString};
+    ///
+    /// unsafe {
+    ///     let cstring = CString::new("hello").expect("CString::new failed");
+    ///     let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
+    ///     assert_eq!(cstr, &*cstring);
+    /// }
+    /// ```
+    #[inline]
+    #[must_use]
+    #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+    #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
+    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // We're in a const fn, so this is the best we can do
+        debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
+        // SAFETY: Calling an inner function with the same prerequisites.
+        unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
+    }
+
+    #[inline]
+    const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // SAFETY: Casting to CStr is safe because its internal representation
+        // is a [u8] too (safe only inside std).
+        // Dereferencing the obtained pointer is safe because it comes from a
+        // reference. Making a reference is then safe because its lifetime
+        // is bound by the lifetime of the given `bytes`.
+        unsafe { &*(bytes as *const [u8] as *const CStr) }
+    }
+
+    /// Returns the inner pointer to this C string.
+    ///
+    /// The returned pointer will be valid for as long as `self` is, and points
+    /// to a contiguous region of memory terminated with a 0 byte to represent
+    /// the end of the string.
+    ///
+    /// **WARNING**
+    ///
+    /// The returned pointer is read-only; writing to it (including passing it
+    /// to C code that writes to it) causes undefined behavior.
+    ///
+    /// It is your responsibility to make sure that the underlying memory is not
+    /// freed too early. For example, the following code will cause undefined
+    /// behavior when `ptr` is used inside the `unsafe` block:
+    ///
+    /// ```no_run
+    /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
+    /// use std::ffi::CString;
+    ///
+    /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
+    /// unsafe {
+    ///     // `ptr` is dangling
+    ///     *ptr;
+    /// }
+    /// ```
+    ///
+    /// This happens because the pointer returned by `as_ptr` does not carry any
+    /// lifetime information and the `CString` is deallocated immediately after
+    /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
+    /// expression is evaluated.
+    /// To fix the problem, bind the `CString` to a local variable:
+    ///
+    /// ```no_run
+    /// # #![allow(unused_must_use)]
+    /// use std::ffi::CString;
+    ///
+    /// let hello = CString::new("Hello").expect("CString::new failed");
+    /// let ptr = hello.as_ptr();
+    /// unsafe {
+    ///     // `ptr` is valid because `hello` is in scope
+    ///     *ptr;
+    /// }
+    /// ```
+    ///
+    /// This way, the lifetime of the `CString` in `hello` encompasses
+    /// the lifetime of `ptr` and the `unsafe` block.
+    #[inline]
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+    pub const fn as_ptr(&self) -> *const c_char {
+        self.inner.as_ptr()
+    }
+
+    /// Converts this C string to a byte slice.
+    ///
+    /// The returned slice will **not** contain the trailing nul terminator that this C
+    /// string has.
+    ///
+    /// > **Note**: This method is currently implemented as a constant-time
+    /// > cast, but it is planned to alter its definition in the future to
+    /// > perform the length calculation whenever this method is called.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+    /// assert_eq!(cstr.to_bytes(), b"foo");
+    /// ```
+    #[inline]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn to_bytes(&self) -> &[u8] {
+        let bytes = self.to_bytes_with_nul();
+        // SAFETY: to_bytes_with_nul returns slice with length at least 1
+        unsafe { bytes.get_unchecked(..bytes.len() - 1) }
+    }
+
+    /// Converts this C string to a byte slice containing the trailing 0 byte.
+    ///
+    /// This function is the equivalent of [`CStr::to_bytes`] except that it
+    /// will retain the trailing nul terminator instead of chopping it off.
+    ///
+    /// > **Note**: This method is currently implemented as a 0-cost cast, but
+    /// > it is planned to alter its definition in the future to perform the
+    /// > length calculation whenever this method is called.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+    /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
+    /// ```
+    #[inline]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn to_bytes_with_nul(&self) -> &[u8] {
+        // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
+        // is safe on all supported targets.
+        unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
+    }
+
+    /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
+    ///
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return the corresponding <code>&[str]</code> slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
+    ///
+    /// [str]: prim@str "str"
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[stable(feature = "cstr_to_str", since = "1.4.0")]
+    pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+        // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
+        // instead of in `from_ptr()`, it may be worth considering if this should
+        // be rewritten to do the UTF-8 check inline with the length calculation
+        // instead of doing it afterwards.
+        str::from_utf8(self.to_bytes())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for CStr {
+    fn eq(&self, other: &CStr) -> bool {
+        self.to_bytes().eq(other.to_bytes())
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for CStr {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for CStr {
+    fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
+        self.to_bytes().partial_cmp(&other.to_bytes())
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for CStr {
+    fn cmp(&self, other: &CStr) -> Ordering {
+        self.to_bytes().cmp(&other.to_bytes())
+    }
+}
+
+#[stable(feature = "cstr_range_from", since = "1.47.0")]
+impl ops::Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
+        let bytes = self.to_bytes_with_nul();
+        // we need to manually check the starting index to account for the null
+        // byte, since otherwise we could get an empty string that doesn't end
+        // in a null.
+        if index.start < bytes.len() {
+            // SAFETY: Non-empty tail of a valid `CStr` is still a valid `CStr`.
+            unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+        } else {
+            panic!(
+                "index out of bounds: the len is {} but the index is {}",
+                bytes.len(),
+                index.start
+            );
+        }
+    }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef<CStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &CStr {
+        self
+    }
+}
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index e61ea9ce87f..d2df2671204 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -14,6 +14,11 @@ use crate::marker::PhantomData;
 use crate::num::*;
 use crate::ops::{Deref, DerefMut};
 
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError};
+
+mod c_str;
+
 macro_rules! type_alias_no_nz {
     {
       $Docfile:tt, $Alias:ident = $Real:ty;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6546a5244fd..78d01c268f5 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -20,7 +20,7 @@
 // FIXME: Fill me in with more detail when the interface settles
 //! This library is built on the assumption of a few existing symbols:
 //!
-//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
+//! * `memcpy`, `memcmp`, `memset`, `strlen` - These are core memory routines which are
 //!   often generated by LLVM. Additionally, this library can make explicit
 //!   calls to these functions. Their signatures are the same as found in C.
 //!   These functions are often provided by the system libc, but can also be
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index dd9b035e86d..f2d65832060 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.69" }
+compiler_builtins = { version = "0.1.71" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 4fb94908c80..3f85c2095cb 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -26,6 +26,7 @@ use crate::borrow::Cow;
 use crate::cell;
 use crate::char;
 use crate::fmt::{self, Debug, Display, Write};
+use crate::io;
 use crate::mem::transmute;
 use crate::num;
 use crate::str;
@@ -612,6 +613,48 @@ impl Error for alloc::collections::TryReserveError {}
 #[unstable(feature = "duration_checked_float", issue = "83400")]
 impl Error for time::FromFloatSecsError {}
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for alloc::ffi::NulError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "nul byte found in data"
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<alloc::ffi::NulError> for io::Error {
+    /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`].
+    fn from(_: alloc::ffi::NulError) -> io::Error {
+        io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
+    }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for core::ffi::FromBytesWithNulError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        self.__description()
+    }
+}
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl Error for core::ffi::FromBytesUntilNulError {}
+
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+impl Error for alloc::ffi::FromVecWithNulError {}
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+impl Error for alloc::ffi::IntoStringError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "C string contained non-utf8 bytes"
+    }
+
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        Some(self.__source())
+    }
+}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the inner type is the same as `T`.
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 13e3dacc30d..5989ba71de0 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -146,12 +146,14 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub use self::c_str::FromBytesWithNulError;
 #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
-pub use self::c_str::FromVecWithNulError;
+pub use alloc::ffi::FromVecWithNulError;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc::ffi::{CString, IntoStringError, NulError};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::c_str::{CStr, CString, IntoStringError, NulError};
+pub use core::ffi::CStr;
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub use core::ffi::FromBytesWithNulError;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::os_str::{OsStr, OsString};
@@ -176,5 +178,4 @@ pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t};
 )]
 pub use core::ffi::{VaList, VaListImpl};
 
-mod c_str;
 mod os_str;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 60e7c2af8e4..411a38038f1 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -261,6 +261,8 @@
 #![feature(char_error_internals)]
 #![feature(char_internals)]
 #![feature(core_intrinsics)]
+#![feature(cstr_from_bytes_until_nul)]
+#![feature(cstr_internals)]
 #![feature(duration_checked_float)]
 #![feature(duration_constants)]
 #![feature(exact_size_is_empty)]
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 0226c4d7a25..f7533696df4 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -95,3 +95,7 @@ pub use crate::string::{String, ToString};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use crate::vec::Vec;
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub use alloc::ffi::CStrExt;