diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index a03c561861e2b..d6f317f1d4489 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -184,7 +184,9 @@ language_item_table! { ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl, GenericRequirement::None; MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl, GenericRequirement::None; ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl, GenericRequirement::None; + ConstStrPtr, sym::const_str_ptr, const_str_ptr_impl, Target::Impl, GenericRequirement::None; MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl, GenericRequirement::None; + MutStrPtr, sym::mut_str_ptr, mut_str_ptr_impl, Target::Impl, GenericRequirement::None; I8, sym::i8, i8_impl, Target::Impl, GenericRequirement::None; I16, sym::i16, i16_impl, Target::Impl, GenericRequirement::None; I32, sym::i32, i32_impl, Target::Impl, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a4280047c7068..5c2cef514f176 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -478,6 +478,7 @@ symbols! { const_raw_ptr_to_usize_cast, const_refs_to_cell, const_slice_ptr, + const_str_ptr, const_trait_bound_opt_out, const_trait_impl, const_transmute, @@ -864,6 +865,7 @@ symbols! { must_use, mut_ptr, mut_slice_ptr, + mut_str_ptr, naked, naked_functions, name, diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 9fd7e8c4daa20..4f845e03ac7d3 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -680,16 +680,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl }) => { - let (lang_def_id1, lang_def_id2) = match mutbl { - hir::Mutability::Not => { - (lang_items.const_ptr_impl(), lang_items.const_slice_ptr_impl()) - } - hir::Mutability::Mut => { - (lang_items.mut_ptr_impl(), lang_items.mut_slice_ptr_impl()) - } + let (lang_def_id1, lang_def_id2, lang_def_id3) = match mutbl { + hir::Mutability::Not => ( + lang_items.const_ptr_impl(), + lang_items.const_slice_ptr_impl(), + lang_items.const_str_ptr_impl(), + ), + hir::Mutability::Mut => ( + lang_items.mut_ptr_impl(), + lang_items.mut_slice_ptr_impl(), + lang_items.mut_str_ptr_impl(), + ), }; self.assemble_inherent_impl_for_primitive(lang_def_id1); self.assemble_inherent_impl_for_primitive(lang_def_id2); + self.assemble_inherent_impl_for_primitive(lang_def_id3); } ty::Int(i) => { let lang_def_id = match i { diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 6a9ba9d49134c..fd4a7cd3efdeb 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -149,6 +149,19 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { assoc_items, ); } + ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) + if matches!(inner.kind(), ty::Str) => + { + self.check_primitive_impl( + item.def_id, + lang_items.const_str_ptr_impl(), + None, + "const_str_ptr", + "*const str", + item.span, + assoc_items, + ); + } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) if matches!(inner.kind(), ty::Slice(_)) => { @@ -162,6 +175,19 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { assoc_items, ); } + ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) + if matches!(inner.kind(), ty::Str) => + { + self.check_primitive_impl( + item.def_id, + lang_items.mut_str_ptr_impl(), + None, + "mut_str_ptr", + "*mut str", + item.span, + assoc_items, + ); + } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => { self.check_primitive_impl( item.def_id, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 78383b54c5d1e..d00a640d1ad5e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -133,6 +133,7 @@ #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_str_from_utf8_unchecked_mut)] +#![cfg_attr(not(bootstrap), feature(const_str_ptr_len))] #![feature(const_swap)] #![feature(const_trait_impl)] #![feature(const_type_id)] @@ -193,6 +194,9 @@ #![feature(simd_ffi)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] +#![cfg_attr(not(bootstrap), feature(str_ptr_len))] +#![cfg_attr(not(bootstrap), feature(str_ptr_as_ptr))] +#![cfg_attr(not(bootstrap), feature(str_ptr_get))] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 344b483662abd..2b4230d648398 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -913,7 +913,7 @@ impl *const [T] { /// The returned value is the number of **elements**, not the number of bytes. /// /// This function is safe, even when the raw slice cannot be cast to a slice - /// reference because the pointer is null or unaligned. + /// reference (e.g. because the pointer is null or unaligned). /// /// # Examples /// @@ -1030,6 +1030,83 @@ impl *const [T] { } } +#[cfg(not(bootstrap))] +#[lang = "const_str_ptr"] +impl *const str { + /// Returns the length of a raw string slice. + /// + /// The returned value is the number of **bytes**, not the number of characters. + /// + /// This function is safe, even when the raw string slice cannot be cast to a string slice + /// reference (e.g. because the pointer is null or unaligned). + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_len)] + /// + /// let str: *const str = "abc"; + /// assert_eq!(str.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_str_ptr_len", issue = "71146")] + pub const fn len(self) -> usize { + metadata(self) + } + + /// Returns a raw pointer to the string slice's buffer. + /// + /// This is equivalent to casting `self` to `*const u8`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_as_ptr)] + /// + /// let str: *const str = "a"; + /// let ptr: *const u8 = str.as_ptr(); + /// assert_eq!(unsafe { *ptr }, b'a'); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_as_ptr", issue = "74265")] + #[rustc_const_unstable(feature = "str_ptr_as_ptr", issue = "74265")] + pub const fn as_ptr(self) -> *const u8 { + self as *const u8 + } + + /// Returns a raw pointer to an substring, without doing bounds + /// checking. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(str_ptr_get)] + /// + /// let x = "abc" as *const str; + /// + /// unsafe { + /// assert_eq!(&*x.get_unchecked(1..), "bc"); + /// } + /// ``` + #[unstable(feature = "str_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + where + I: SliceIndex, + { + // SAFETY: the caller ensures that `self` is dereferenceable and `index` is in-bounds. + unsafe { index.get_unchecked(self) } + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index f3b2bdfefe5df..5fef037e97e0f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1176,7 +1176,7 @@ impl *mut [T] { /// The returned value is the number of **elements**, not the number of bytes. /// /// This function is safe, even when the raw slice cannot be cast to a slice - /// reference because the pointer is null or unaligned. + /// reference (e.g. because the pointer is null or unaligned). /// /// # Examples /// @@ -1346,6 +1346,90 @@ impl *mut [T] { } } +#[cfg(not(bootstrap))] +#[lang = "mut_str_ptr"] +impl *mut str { + /// Returns the length of a raw string slice. + /// + /// The returned value is the number of **bytes**, not the number of characters. + /// + /// This function is safe, even when the raw string slice cannot be cast to a string slice + /// reference (e.g. because the pointer is null or unaligned). + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_len)] + /// + /// let mut arr = [b'a', b'b', b'c']; + /// let s: &mut str = std::str::from_utf8_mut(&mut arr).unwrap(); + /// let s: *mut str = s as *mut str; + /// + /// assert_eq!(s.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_str_ptr_len", issue = "71146")] + pub const fn len(self) -> usize { + metadata(self) + } + + /// Returns a raw pointer to the string slice's buffer. + /// + /// This is equivalent to casting `self` to `*mut u8`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_as_ptr)] + /// + /// let mut arr = [b'a', b'b', b'c']; + /// let s: &mut str = std::str::from_utf8_mut(&mut arr).unwrap(); + /// let s: *mut str = s as *mut str; + /// + /// assert_eq!(s.as_mut_ptr(), arr.as_mut_ptr()); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_as_ptr", issue = "74265")] + #[rustc_const_unstable(feature = "str_ptr_as_ptr", issue = "74265")] + pub const fn as_mut_ptr(self) -> *mut u8 { + self as *mut u8 + } + + /// Returns a raw pointer to an substring, without doing bounds + /// checking. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(str_ptr_get)] + /// + /// let mut x = [b'a', b'b', b'c']; + /// let x: &mut str = std::str::from_utf8_mut(&mut x).unwrap(); + /// let x: *mut str = x as *mut str; + /// + /// unsafe { + /// assert_eq!(&*x.get_unchecked_mut(1..), "bc"); + /// } + /// ``` + #[unstable(feature = "str_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + where + I: SliceIndex, + { + // SAFETY: the caller ensures that `self` is dereferenceable and `index` is in-bounds. + unsafe { index.get_unchecked_mut(self) } + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *mut T { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 58110b0680943..c14135ee36f82 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -634,6 +634,104 @@ impl NonNull<[T]> { } } +#[cfg(not(bootstrap))] +impl NonNull { + /// Returns the length of a non-null raw slice. + /// + /// The returned value is the number of **bytes**, not the number of characters. + /// + /// This function is safe, even when the non-null raw slice cannot be dereferenced to a slice + /// because the pointer does not have a valid address. + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_len)] + /// use std::ptr::NonNull; + /// + /// let slice: NonNull = NonNull::from("abc"); + /// assert_eq!(slice.len(), 3); + /// ``` + #[unstable(feature = "str_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_str_ptr_len", issue = "71146")] + #[inline] + pub const fn len(self) -> usize { + self.as_ptr().len() + } + + /// Returns a non-null pointer to the string slice's buffer. + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_as_ptr)] + /// use std::ptr::NonNull; + /// + /// let s: &str = "abc"; + /// let str: NonNull = NonNull::from("abc"); + /// assert_eq!(str.as_non_null_ptr(), NonNull::new(s.as_ptr() as *mut u8).unwrap()); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_as_ptr", issue = "74265")] + #[rustc_const_unstable(feature = "str_ptr_as_ptr", issue = "74265")] + pub const fn as_non_null_ptr(self) -> NonNull { + // SAFETY: We know `self` is non-null. + unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) } + } + + /// Returns a raw pointer to the string slice's buffer. + /// + /// # Examples + /// + /// ```rust + /// #![feature(str_ptr_as_ptr)] + /// use std::ptr::NonNull; + /// + /// let s: &str = "abc"; + /// let str: NonNull = NonNull::from("abc"); + /// assert_eq!(str.as_mut_ptr(), s.as_ptr() as *mut u8); + /// ``` + #[inline] + #[unstable(feature = "str_ptr_as_ptr", issue = "74265")] + #[rustc_const_unstable(feature = "str_ptr_as_ptr", issue = "74265")] + pub const fn as_mut_ptr(self) -> *mut u8 { + self.as_non_null_ptr().as_ptr() + } + + /// Returns a raw pointer to an element or substring, without doing bounds + /// checking. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(str_ptr_get, str_ptr_as_ptr)] + /// use std::ptr::NonNull; + /// + /// let x = NonNull::from("abc"); + /// + /// unsafe { + /// assert_eq!(x.get_unchecked_mut(1..).as_mut_ptr(), x.as_mut_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "str_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + where + I: SliceIndex, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + // As a consequence, the resulting pointer cannot be null. + unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) } + } +} + #[stable(feature = "nonnull", since = "1.25.0")] impl Clone for NonNull { #[inline]