From e15212f9b376f2965028da3c1ae2376f798f575f Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 29 May 2021 17:33:06 +0300 Subject: [PATCH 1/4] Add `const_str_ptr` and `mut_str_ptr` lang items These items allow to make inherent impls for `*const str` and `*mut str`. --- compiler/rustc_hir/src/lang_items.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 2 ++ .../rustc_typeck/src/check/method/probe.rs | 19 +++++++++----- .../src/coherence/inherent_impls.rs | 26 +++++++++++++++++++ 4 files changed, 42 insertions(+), 7 deletions(-) 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, From 8ee7afec6506586253081c374a277893541dc2b6 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 29 May 2021 17:38:42 +0300 Subject: [PATCH 2/4] Add raw str methods This patch adds the following methods to `*const str` and `*mut str`: - `len` - `as_ptr` (`as_mut_ptr`) - `get_unchecked` (`get_unchecked_mut`) Similar methods have already existed for raw slices. --- library/core/src/lib.rs | 4 ++ library/core/src/ptr/const_ptr.rs | 80 ++++++++++++++++++++++++++++ library/core/src/ptr/mut_ptr.rs | 87 +++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) 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..ae1f2c654f4ca 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1030,6 +1030,86 @@ 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 slice + /// reference 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 + /// + /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries + /// is safe, but dereferencing the pointer returned by such call is unsound. + /// + /// # 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..cf479bc33674e 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1346,6 +1346,93 @@ 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 slice + /// reference 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 + /// + /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries + /// is safe, but dereferencing the pointer returned by such call is unsound. + /// + /// # 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 { From fd3fb2e7e2ed255633a073006797bacd8895bdbf Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 15 Aug 2021 20:09:39 +0300 Subject: [PATCH 3/4] Add nonnull raw str methods This patch adds the following methods to `NonNull`: - `len` - `as_non_null_ptr` - `as_mut_ptr` - `get_unchecked_mut` Similar methods have already existed for raw slices, raw strings and nonnull raw slices. --- library/core/src/ptr/non_null.rs | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 58110b0680943..d84ffb17ed617 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -634,6 +634,107 @@ 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 + /// + /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries + /// is safe, but dereferencing the pointer returned by such call is unsound. + /// + /// # 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] From bb73eababb58baa8aee18854f28b7aa29cc1c062 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 17 Dec 2021 22:46:02 +0300 Subject: [PATCH 4/4] Adjust documentation for some pointer-to-slice methods This commit changes documentation of the following methods as proposed by the PR review - `<*const [T]>::len` - `<*mut [T]>::len` - `<*const str>::len` - `<*mut str>::len` - `<*const str>::get_unchecked` - `<*mut str>::get_unchecked_mut` - `NonNull::::get_unchecked_mut` --- library/core/src/ptr/const_ptr.rs | 9 +++------ library/core/src/ptr/mut_ptr.rs | 9 +++------ library/core/src/ptr/non_null.rs | 3 --- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ae1f2c654f4ca..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 /// @@ -1037,8 +1037,8 @@ impl *const str { /// /// 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 slice - /// reference because the pointer is null or unaligned. + /// 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 /// @@ -1085,9 +1085,6 @@ impl *const str { /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// - /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries - /// is safe, but dereferencing the pointer returned by such call is unsound. - /// /// # Examples /// /// ``` diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index cf479bc33674e..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 /// @@ -1353,8 +1353,8 @@ impl *mut str { /// /// 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 slice - /// reference because the pointer is null or unaligned. + /// 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 /// @@ -1406,9 +1406,6 @@ impl *mut str { /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// - /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries - /// is safe, but dereferencing the pointer returned by such call is unsound. - /// /// # Examples /// /// ``` diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d84ffb17ed617..c14135ee36f82 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -708,9 +708,6 @@ impl NonNull { /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// - /// Note that calling this function with an index that does not lie on an UTF-8 sequence boundaries - /// is safe, but dereferencing the pointer returned by such call is unsound. - /// /// # Examples /// /// ```