From a3797ff5a63f6bcdc2628614f4fb6f01f44892b3 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 1 Oct 2024 22:32:17 +0200 Subject: [PATCH 1/7] str --- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/lib.rs | 1 + library/alloc/src/str.rs | 11 +- library/alloc/src/string.rs | 4 +- library/alloc/src/sync.rs | 2 +- library/core/src/char/methods.rs | 3 +- library/core/src/ffi/c_str.rs | 4 +- library/core/src/fmt/mod.rs | 2 +- library/core/src/fmt/num.rs | 2 +- library/core/src/net/display_buffer.rs | 2 +- library/core/src/slice/ascii.rs | 2 +- library/core/src/str/converts.rs | 46 ++-- library/core/src/str/iter.rs | 6 +- library/core/src/str/lossy.rs | 3 +- library/core/src/str/mod.rs | 213 +++++++++++++++++- library/core/src/time.rs | 2 +- library/std/src/fs/tests.rs | 2 +- library/std/src/io/buffered/bufreader.rs | 2 +- library/std/src/io/buffered/tests.rs | 4 +- library/std/src/io/cursor.rs | 3 +- library/std/src/io/impls.rs | 2 +- library/std/src/io/mod.rs | 2 +- library/std/src/lib.rs | 1 + library/std/src/process.rs | 2 +- library/std/src/process/tests.rs | 1 - library/std/src/sys/backtrace.rs | 2 +- library/std/src/sys/os_str/bytes.rs | 2 +- library/std/src/sys/pal/uefi/stdio.rs | 4 +- library/std/src/sys/pal/unix/thread.rs | 3 +- library/std/src/sys/pal/wasi/fs.rs | 2 +- library/std/src/sys_common/wtf8.rs | 4 +- library/std/src/thread/mod.rs | 3 +- .../feature-gate-inherent-str-constructors.rs | 6 + ...ture-gate-inherent-str-constructors.stderr | 14 ++ 35 files changed, 292 insertions(+), 73 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs create mode 100644 tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4ab0bc473057e..1352906ac8f54 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -527,6 +527,8 @@ declare_features! ( (unstable, import_trait_associated_functions, "CURRENT_RUSTC_VERSION", Some(134691)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), + /// Adds `from_utf8*` functions as inherent methods on the `str` type. + (unstable, inherent_str_constructors, "1.82.0", Some(131114)), /// Allow anonymous constants from an inline `const` block in pattern position (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5ce5dbc9d66a..b3ca23d588a02 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1110,6 +1110,7 @@ symbols! { infer_outlives_requirements, infer_static_outlives_requirements, inherent_associated_types, + inherent_str_constructors, inherit, inlateout, inline, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b4f08debc932a..232017f38bdd8 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -118,6 +118,7 @@ #![feature(fn_traits)] #![feature(formatting_options)] #![feature(hasher_prefixfree_extras)] +#![feature(inherent_str_constructors)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 6fee8d3fe3346..81c3f1efc4831 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -12,6 +12,8 @@ use core::iter::FusedIterator; use core::mem::MaybeUninit; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::ParseBoolError; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] pub use core::str::SplitAsciiWhitespace; #[stable(feature = "split_inclusive", since = "1.51.0")] @@ -22,7 +24,7 @@ pub use core::str::SplitWhitespace; pub use core::str::pattern; use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher, Utf8Pattern}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut}; +pub use core::str::{Bytes, CharIndices, Chars}; #[stable(feature = "str_escape", since = "1.34.0")] pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; #[stable(feature = "rust1", since = "1.0.0")] @@ -35,8 +37,6 @@ pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{ParseBoolError, from_utf8_unchecked, from_utf8_unchecked_mut}; -#[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplit, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; @@ -46,6 +46,9 @@ pub use core::str::{RSplitTerminator, SplitTerminator}; pub use core::str::{Utf8Chunk, Utf8Chunks}; #[unstable(feature = "str_from_raw_parts", issue = "119206")] pub use core::str::{from_raw_parts, from_raw_parts_mut}; +#[allow(deprecated_in_future)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{from_utf8, from_utf8_mut, from_utf8_unchecked, from_utf8_unchecked_mut}; use core::unicode::conversions; use core::{mem, ptr}; @@ -698,7 +701,7 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { // SAFETY: we know this is a valid char boundary // since we only skipped over leading ascii bytes - let rest = core::str::from_utf8_unchecked(slice); + let rest = str::from_utf8_unchecked(slice); (ascii_string, rest) } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 0c9535dfaa628..983d9b85e3936 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -62,7 +62,7 @@ use crate::alloc::Allocator; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, CharIndices, Chars, Utf8Error, from_utf8_unchecked_mut}; +use crate::str::{CharIndices, Chars, Utf8Error}; #[cfg(not(no_global_oom_handling))] use crate::str::{FromStr, from_boxed_utf8_unchecked}; use crate::vec::{self, Vec}; @@ -2110,7 +2110,7 @@ impl String { #[inline] pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); - unsafe { from_utf8_unchecked_mut(slice) } + unsafe { str::from_utf8_unchecked_mut(slice) } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8eee7cff2080d..a722d4c27dafa 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3508,7 +3508,7 @@ impl Default for Arc { #[inline] fn default() -> Self { let arc: Arc<[u8]> = Default::default(); - debug_assert!(core::str::from_utf8(&*arc).is_ok()); + debug_assert!(str::from_utf8(&*arc).is_ok()); let (ptr, alloc) = Arc::into_inner_with_allocator(arc); unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner, alloc) } } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index fb8a740aced13..49427daf6b057 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -3,7 +3,6 @@ use super::*; use crate::panic::const_panic; use crate::slice; -use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; use crate::unicode::{self, conversions}; @@ -701,7 +700,7 @@ impl char { #[inline] pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str { // SAFETY: `char` is not a surrogate, so this is valid UTF-8. - unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } + unsafe { str::from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } /// Encodes this character as UTF-16 into the provided `u16` buffer, diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 7180593edf0d0..0ecd515299036 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -8,7 +8,7 @@ use crate::iter::FusedIterator; use crate::marker::PhantomData; use crate::ptr::NonNull; use crate::slice::memchr; -use crate::{fmt, ops, slice, str}; +use crate::{fmt, ops, slice}; // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link // depends on where the item is being documented. however, since this is libcore, we can't @@ -651,7 +651,7 @@ impl CStr { /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] - pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { + pub const fn to_str(&self) -> Result<&str, crate::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 diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a033b8bd30514..ba241efafab05 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::EscapeDebugExtArgs; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, mem, result}; mod builders; #[cfg(not(no_fp_fmt_parse))] diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 683e45b35f70a..e215624af135c 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -3,7 +3,7 @@ use crate::mem::MaybeUninit; use crate::num::fmt as numfmt; use crate::ops::{Div, Rem, Sub}; -use crate::{fmt, ptr, slice, str}; +use crate::{fmt, ptr, slice}; #[doc(hidden)] trait DisplayInt: diff --git a/library/core/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs index 625ad5401f5c0..a113057c27af4 100644 --- a/library/core/src/net/display_buffer.rs +++ b/library/core/src/net/display_buffer.rs @@ -1,5 +1,5 @@ +use crate::fmt; use crate::mem::MaybeUninit; -use crate::{fmt, str}; /// Used for slow path in `Display` implementations when alignment is required. pub(super) struct DisplayBuffer { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 51b25fa40e3d9..1667d38b2d409 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -302,7 +302,7 @@ impl<'a> fmt::Display for EscapeAscii<'a> { // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) }; // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII - let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) }; + let prefix = unsafe { str::from_utf8_unchecked(prefix) }; f.write_str(prefix)?; // the fast part diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index de68f80aa0c8e..5d539c3c38428 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,8 +1,7 @@ //! Ways to create a `str` from bytes slice. use super::Utf8Error; -use super::validations::run_utf8_validation; -use crate::{mem, ptr}; +use crate::ptr; /// Converts a slice of bytes to a string slice. /// @@ -83,16 +82,10 @@ use crate::{mem, ptr}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] -#[rustc_diagnostic_item = "str_from_utf8"] +#[deprecated(since = "TBD", note = "replaced by the `from_utf8` method on the `str` type")] +// #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - // FIXME(const-hack): This should use `?` again, once it's `const` - match run_utf8_validation(v) { - Ok(_) => { - // SAFETY: validation succeeded. - Ok(unsafe { from_utf8_unchecked(v) }) - } - Err(err) => Err(err), - } + str::from_utf8(v) } /// Converts a mutable slice of bytes to a mutable string slice. @@ -127,13 +120,14 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] -#[rustc_diagnostic_item = "str_from_utf8_mut"] +#[deprecated(since = "TBD", note = "replaced by the `from_utf8_mut` method on the `str` type")] +// #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` - match run_utf8_validation(v) { + match super::run_utf8_validation(v) { Ok(_) => { // SAFETY: validation succeeded. - Ok(unsafe { from_utf8_unchecked_mut(v) }) + Ok(unsafe { str::from_utf8_unchecked_mut(v) }) } Err(err) => Err(err), } @@ -168,11 +162,14 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] -#[rustc_diagnostic_item = "str_from_utf8_unchecked"] +#[deprecated( + since = "TBD", + note = "replaced by the `from_utf8_unchecked` method on the `str` type" +)] +// #[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { - // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. - // Also relies on `&str` and `&[u8]` having the same layout. - unsafe { mem::transmute(v) } + // SAFETY: same requirements + unsafe { str::from_utf8_unchecked(v) } } /// Converts a slice of bytes to a string slice without checking @@ -196,13 +193,14 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked_mut", since = "1.83.0")] -#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] +#[deprecated( + since = "TBD", + note = "replaced by the `from_utf8_unchecked_mut` method on the `str` type" +)] +// #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { - // SAFETY: the caller must guarantee that the bytes `v` - // are valid UTF-8, thus the cast to `*mut str` is safe. - // Also, the pointer dereference is safe because that pointer - // comes from a reference which is guaranteed to be valid for writes. - unsafe { &mut *(v as *mut [u8] as *mut str) } + // SAFETY: same requirements + unsafe { str::from_utf8_unchecked_mut(v) } } /// Creates a `&str` from a pointer and a length. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..a115c77b738f5 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -4,7 +4,7 @@ use super::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use super::validations::{next_code_point, next_code_point_reverse}; use super::{ BytesIsNotEmpty, CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode, - IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, from_utf8_unchecked, + IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, }; use crate::fmt::{self, Write}; use crate::iter::{ @@ -158,7 +158,7 @@ impl<'a> Chars<'a> { #[inline] pub fn as_str(&self) -> &'a str { // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. - unsafe { from_utf8_unchecked(self.iter.as_slice()) } + unsafe { str::from_utf8_unchecked(self.iter.as_slice()) } } } @@ -1413,7 +1413,7 @@ impl<'a> SplitAsciiWhitespace<'a> { } // SAFETY: Slice is created from str. - Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }) + Some(unsafe { str::from_utf8_unchecked(&self.inner.iter.iter.v) }) } } diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index ed2cefc59a51c..816a3aba3680c 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,4 +1,3 @@ -use super::from_utf8_unchecked; use super::validations::utf8_char_width; use crate::fmt; use crate::fmt::{Formatter, Write}; @@ -281,7 +280,7 @@ impl<'a> Iterator for Utf8Chunks<'a> { Some(Utf8Chunk { // SAFETY: All bytes up to `valid_up_to` are valid UTF-8. - valid: unsafe { from_utf8_unchecked(valid) }, + valid: unsafe { str::from_utf8_unchecked(valid) }, invalid, }) } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 8a473b398bb5f..6ef750f4e459c 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,6 +13,8 @@ mod iter; mod traits; mod validations; +use validations::run_utf8_validation; + use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::ops::Range; @@ -25,8 +27,10 @@ mod lossy; #[unstable(feature = "str_from_raw_parts", issue = "119206")] pub use converts::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated_in_future)] pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] +#[allow(deprecated_in_future)] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; @@ -160,6 +164,201 @@ impl str { self.len() == 0 } + /// Converts a slice of bytes to a string slice. + /// + /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice + /// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between + /// the two. Not all byte slices are valid string slices, however: [`&str`] requires + /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid + /// UTF-8, and then does the conversion. + /// + /// [`&str`]: str + /// [byteslice]: slice + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want to + /// incur the overhead of the validity check, there is an unsafe version of + /// this function, [`from_utf8_unchecked`], which has the same + /// behavior but skips the check. + /// + /// If you need a `String` instead of a `&str`, consider + /// [`String::from_utf8`][string]. + /// + /// [string]: ../../std/string/struct.String.html#method.from_utf8 + /// + /// Because you can stack-allocate a `[u8; N]`, and you can take a + /// [`&[u8]`][byteslice] of it, this function is one way to have a + /// stack-allocated string. There is an example of this in the + /// examples section below. + /// + /// [byteslice]: slice + /// + /// # Errors + /// + /// Returns `Err` if the slice is not UTF-8 with a description as to why the + /// provided slice is not UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// assert!(str::from_utf8(&sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + /// + /// A "stack allocated string": + /// + /// ``` + /// // some bytes, in a stack-allocated array + /// let sparkle_heart = [240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart: &str = str::from_utf8(&sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] + #[rustc_allow_const_fn_unstable(str_internals)] + #[rustc_diagnostic_item = "str_from_utf8"] + pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + // FIXME(const-hack): This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { Self::from_utf8_unchecked(v) }) + } + Err(err) => Err(err), + } + } + + /// Converts a mutable slice of bytes to a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // "Hello, Rust!" as a mutable vector + /// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; + /// + /// // As we know these bytes are valid, we can use `unwrap()` + /// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); + /// + /// assert_eq!("Hello, Rust!", outstr); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use std::str; + /// + /// // Some invalid bytes in a mutable vector + /// let mut invalid = vec![128, 223]; + /// + /// assert!(str::from_utf8_mut(&mut invalid).is_err()); + /// ``` + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + #[rustc_diagnostic_item = "str_from_utf8_mut"] + pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + // FIXME(const-hack): This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { Self::from_utf8_unchecked_mut(v) }) + } + Err(err) => Err(err), + } + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8. + /// + /// See the safe version, [`from_utf8`], for more information. + /// + /// # Safety + /// + /// The bytes passed in must be valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// let sparkle_heart = unsafe { + /// str::from_utf8_unchecked(&sparkle_heart) + /// }; + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] + #[rustc_diagnostic_item = "str_from_utf8_unchecked"] + pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { + // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. + // Also relies on `&str` and `&[u8]` having the same layout. + unsafe { mem::transmute(v) } + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8; mutable version. + /// + /// See the immutable version, [`from_utf8_unchecked()`] for more information. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// let mut heart = vec![240, 159, 146, 150]; + /// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; + /// + /// assert_eq!("💖", heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] + #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] + pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + // SAFETY: the caller must guarantee that the bytes `v` + // are valid UTF-8, thus the cast to `*mut str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for writes. + unsafe { &mut *(v as *mut [u8] as *mut str) } + } + /// Checks that `index`-th byte is the first byte in a UTF-8 code point /// sequence or the end of the string. /// @@ -805,8 +1004,8 @@ impl str { // SAFETY: caller guarantees `mid` is on a char boundary. unsafe { ( - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), + str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), + str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), ) } } @@ -2561,7 +2760,7 @@ impl str { pub const fn trim_ascii_start(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_start()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii_start()) } } /// Returns a string slice with trailing ASCII whitespace removed. @@ -2586,7 +2785,7 @@ impl str { pub const fn trim_ascii_end(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_end()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii_end()) } } /// Returns a string slice with leading and trailing ASCII whitespace @@ -2612,7 +2811,7 @@ impl str { pub const fn trim_ascii(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } } /// Returns an iterator that escapes each char in `self` with [`char::escape_debug`]. @@ -2808,7 +3007,7 @@ impl Default for &mut str { #[inline] fn default() -> Self { // SAFETY: The empty string is valid UTF-8. - unsafe { from_utf8_unchecked_mut(&mut []) } + unsafe { str::from_utf8_unchecked_mut(&mut []) } } } @@ -2862,7 +3061,7 @@ impl_fn_for_zst! { #[derive(Clone)] struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str { // SAFETY: not safe - unsafe { from_utf8_unchecked(bytes) } + unsafe { str::from_utf8_unchecked(bytes) } }; } diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 22bd46c567eaa..172eb89d9439c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1327,7 +1327,7 @@ impl fmt::Debug for Duration { if end > 0 { // SAFETY: We are only writing ASCII digits into the buffer and // it was initialized with '0's, so it contains valid UTF8. - let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + let s = unsafe { str::from_utf8_unchecked(&buf[..end]) }; // If the user request a precision > 9, we pad '0's at the end. let w = f.precision().unwrap_or(pos); diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 28f16da1ed8d2..6dd3ce83c77cc 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -16,7 +16,7 @@ use crate::path::Path; use crate::sync::Arc; use crate::sys_common::io::test::{TempDir, tmpdir}; use crate::time::{Duration, Instant, SystemTime}; -use crate::{env, str, thread}; +use crate::{env, thread}; macro_rules! check { ($e:expr) => { diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 8b46738ab8aee..cf1d5d8c5927a 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -437,7 +437,7 @@ impl Read for BufReader { // buffer. let mut bytes = Vec::new(); self.read_to_end(&mut bytes)?; - let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; + let string = str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; *buf += string; Ok(string.len()) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 17f6107aa030c..03c9d326a6157 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1023,9 +1023,7 @@ struct WriteRecorder { impl Write for WriteRecorder { fn write(&mut self, buf: &[u8]) -> io::Result { - use crate::str::from_utf8; - - self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); + self.events.push(RecordedEvent::Write(str::from_utf8(buf).unwrap().to_string())); Ok(buf.len()) } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index b2ffeb0f95d0d..06343e0ad478b 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -389,8 +389,7 @@ where } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - let content = - crate::str::from_utf8(Cursor::split(self).1).map_err(|_| io::Error::INVALID_UTF8)?; + let content = str::from_utf8(Cursor::split(self).1).map_err(|_| io::Error::INVALID_UTF8)?; let len = content.len(); buf.try_reserve(len)?; buf.push_str(content); diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index b952c85addf65..70cada395b045 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -4,7 +4,7 @@ mod tests; use crate::alloc::Allocator; use crate::collections::VecDeque; use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; -use crate::{cmp, fmt, mem, str}; +use crate::{cmp, fmt, mem}; // ============================================================================= // Forwarding implementations diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 231c8712ebd55..9f5eec9714ac6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -331,7 +331,7 @@ pub use self::{ use crate::mem::take; use crate::ops::{Deref, DerefMut}; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; -use crate::{cmp, fmt, slice, str, sys}; +use crate::{cmp, fmt, slice, sys}; mod buffered; pub(crate) mod copy; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 39f234e4ba661..53f5d11fbad2a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -337,6 +337,7 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_must_use)] +#![feature(inherent_str_constructors)] #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_slice)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e0dd2e14817a8..a920845eb7bfa 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -170,7 +170,7 @@ use crate::sys::process as imp; #[stable(feature = "command_access", since = "1.57.0")] pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -use crate::{fmt, fs, str}; +use crate::{fmt, fs}; /// Representation of a running or exited child process. /// diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index e8cbfe337bccf..19eaa2c1bd790 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -2,7 +2,6 @@ use super::{Command, Output, Stdio}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind}; use crate::mem::MaybeUninit; -use crate::str; fn known_command() -> Command { if cfg!(windows) { Command::new("help") } else { Command::new("echo") } diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8f..4da9433112a76 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -190,7 +190,7 @@ pub fn output_filename( } #[cfg(not(unix))] BytesOrWideString::Bytes(bytes) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() + Path::new(str::from_utf8(bytes).unwrap_or("")).into() } #[cfg(windows)] BytesOrWideString::Wide(wide) => { diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 5b65d862be102..290be0a519173 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -9,7 +9,7 @@ use crate::fmt::Write; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::{AsInner, IntoInner}; -use crate::{fmt, mem, str}; +use crate::{fmt, mem}; #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/uefi/stdio.rs b/library/std/src/sys/pal/uefi/stdio.rs index 703e8ba8e5710..7a3d6e59939a4 100644 --- a/library/std/src/sys/pal/uefi/stdio.rs +++ b/library/std/src/sys/pal/uefi/stdio.rs @@ -155,9 +155,9 @@ fn write( buf: &[u8], ) -> io::Result { // Get valid UTF-8 buffer - let utf8 = match crate::str::from_utf8(buf) { + let utf8 = match str::from_utf8(buf) { Ok(x) => x, - Err(e) => unsafe { crate::str::from_utf8_unchecked(&buf[..e.valid_up_to()]) }, + Err(e) => unsafe { str::from_utf8_unchecked(&buf[..e.valid_up_to()]) }, }; let mut utf16: Vec = utf8.encode_utf16().collect(); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index f657f82e6e368..9980af6268671 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -524,13 +524,14 @@ mod cgroups { //! * paths containing control characters or spaces, since those would be escaped in procfs //! output and we don't unescape + use str::from_utf8; + use crate::borrow::Cow; use crate::ffi::OsString; use crate::fs::{File, exists}; use crate::io::{BufRead, Read}; use crate::os::unix::ffi::OsStringExt; use crate::path::{Path, PathBuf}; - use crate::str::from_utf8; #[derive(PartialEq)] enum Cgroup { diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 7779d2b97d7f9..7a8ae12eaa229 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -844,7 +844,7 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { // necessary for entry in ReadDir::new(fd, dummy_root) { let entry = entry?; - let path = crate::str::from_utf8(&entry.name).map_err(|_| { + let path = str::from_utf8(&entry.name).map_err(|_| { io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 6c60d901ee904..046934ca1cc56 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -29,7 +29,7 @@ use crate::iter::FusedIterator; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::AsInner; -use crate::{fmt, mem, ops, slice, str}; +use crate::{fmt, mem, ops, slice}; const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; @@ -656,7 +656,7 @@ impl Wtf8 { /// /// This does not copy the data. #[inline] - pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + pub fn as_str(&self) -> Result<&str, core::str::Utf8Error> { str::from_utf8(&self.bytes) } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 59b395336f2e3..b2dcdde17f165 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -171,7 +171,7 @@ use crate::sys::sync::Parker; use crate::sys::thread as imp; use crate::sys_common::{AsInner, IntoInner}; use crate::time::{Duration, Instant}; -use crate::{env, fmt, io, panic, panicking, str}; +use crate::{env, fmt, io, panic, panicking}; #[stable(feature = "scoped_threads", since = "1.63.0")] mod scoped; @@ -1257,7 +1257,6 @@ impl ThreadId { // This module ensures private fields are kept private, which is necessary to enforce the safety requirements. mod thread_name_string { use crate::ffi::{CStr, CString}; - use crate::str; /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated. pub(crate) struct ThreadNameString { diff --git a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs new file mode 100644 index 0000000000000..fb76e9628ac74 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs @@ -0,0 +1,6 @@ +// Test that inherent str constructors cannot be used when inherent_str_constructors +// feature gate is not used. + +fn main() { + str::from_utf8(b"hi").unwrap(); +} diff --git a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr new file mode 100644 index 0000000000000..bccbf11f1b9be --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr @@ -0,0 +1,14 @@ +error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope + --> $DIR/feature-gate-inherent-str-constructors.rs:5:10 + | +LL | str::from_utf8(b"hi").unwrap(); + | ^^^^^^^^^ function or associated item not found in `str` + | +help: you are looking for the module in `std`, not the primitive type + | +LL | std::str::from_utf8(b"hi").unwrap(); + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. From 38d938833b149ce3f907ca98a926056669635f09 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 1 Oct 2024 22:57:02 +0200 Subject: [PATCH 2/7] fix --- library/std/src/sys/pal/unix/thread.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 9980af6268671..2f74273fbe1c6 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -524,8 +524,6 @@ mod cgroups { //! * paths containing control characters or spaces, since those would be escaped in procfs //! output and we don't unescape - use str::from_utf8; - use crate::borrow::Cow; use crate::ffi::OsString; use crate::fs::{File, exists}; @@ -560,7 +558,7 @@ mod cgroups { let version = match fields.nth(1) { Some(b"") => Cgroup::V2, Some(controllers) - if from_utf8(controllers) + if str::from_utf8(controllers) .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) => { Cgroup::V1 From af25259165474e1ad5379ac9ff5fa27af730fd70 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 1 Oct 2024 23:07:49 +0200 Subject: [PATCH 3/7] and windows --- library/std/src/sys/pal/windows/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index fd3f559ba1901..20ed81de6ecc1 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -7,7 +7,7 @@ use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::sys::handle::Handle; use crate::sys::{c, cvt}; -use crate::{cmp, io, ptr, str}; +use crate::{cmp, io, ptr}; #[cfg(test)] mod tests; From af9a5edde94ee5217ea99fc4f7c802dc8cba9823 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 1 Oct 2024 23:32:10 +0200 Subject: [PATCH 4/7] huh --- library/core/src/str/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 6ef750f4e459c..f07a665b18446 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -27,10 +27,8 @@ mod lossy; #[unstable(feature = "str_from_raw_parts", issue = "119206")] pub use converts::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[allow(deprecated_in_future)] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; From 94d0b8fd1f987e4427883de01c682388b48a3ede Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 21 Jan 2025 13:58:56 +0100 Subject: [PATCH 5/7] undeprecate --- library/alloc/src/str.rs | 1 - library/core/src/str/converts.rs | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 81c3f1efc4831..5ae82353461c7 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -46,7 +46,6 @@ pub use core::str::{RSplitTerminator, SplitTerminator}; pub use core::str::{Utf8Chunk, Utf8Chunks}; #[unstable(feature = "str_from_raw_parts", issue = "119206")] pub use core::str::{from_raw_parts, from_raw_parts_mut}; -#[allow(deprecated_in_future)] #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8, from_utf8_mut, from_utf8_unchecked, from_utf8_unchecked_mut}; use core::unicode::conversions; diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 5d539c3c38428..bc33affb3a15c 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,8 +82,6 @@ use crate::ptr; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] -#[deprecated(since = "TBD", note = "replaced by the `from_utf8` method on the `str` type")] -// #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { str::from_utf8(v) } @@ -120,8 +118,6 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] -#[deprecated(since = "TBD", note = "replaced by the `from_utf8_mut` method on the `str` type")] -// #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` match super::run_utf8_validation(v) { @@ -162,11 +158,6 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] -#[deprecated( - since = "TBD", - note = "replaced by the `from_utf8_unchecked` method on the `str` type" -)] -// #[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: same requirements unsafe { str::from_utf8_unchecked(v) } @@ -193,11 +184,6 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked_mut", since = "1.83.0")] -#[deprecated( - since = "TBD", - note = "replaced by the `from_utf8_unchecked_mut` method on the `str` type" -)] -// #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: same requirements unsafe { str::from_utf8_unchecked_mut(v) } From 5f6b0124ba35adf09e15f28ff943b6820abe4aac Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 21 Jan 2025 15:00:03 +0100 Subject: [PATCH 6/7] const unstable --- library/core/src/str/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index f07a665b18446..f9b78e89d655f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -233,7 +233,7 @@ impl str { /// assert_eq!("💖", sparkle_heart); /// ``` #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] + #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] #[rustc_allow_const_fn_unstable(str_internals)] #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { @@ -278,7 +278,7 @@ impl str { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` @@ -319,7 +319,7 @@ impl str { #[inline] #[must_use] #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] + #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] #[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. @@ -347,7 +347,7 @@ impl str { #[inline] #[must_use] #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] + #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` From e0e476546c8a44811ce2a49094ff14c29590fce3 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 21 Jan 2025 23:29:32 +0100 Subject: [PATCH 7/7] address comments --- compiler/rustc_feature/src/unstable.rs | 2 -- compiler/rustc_span/src/symbol.rs | 1 - library/core/src/str/converts.rs | 13 +++++-------- library/core/src/str/mod.rs | 8 -------- .../feature-gate-inherent-str-constructors.rs | 6 ------ .../feature-gate-inherent-str-constructors.stderr | 14 -------------- 6 files changed, 5 insertions(+), 39 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs delete mode 100644 tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1352906ac8f54..4ab0bc473057e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -527,8 +527,6 @@ declare_features! ( (unstable, import_trait_associated_functions, "CURRENT_RUSTC_VERSION", Some(134691)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), - /// Adds `from_utf8*` functions as inherent methods on the `str` type. - (unstable, inherent_str_constructors, "1.82.0", Some(131114)), /// Allow anonymous constants from an inline `const` block in pattern position (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b3ca23d588a02..f5ce5dbc9d66a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1110,7 +1110,6 @@ symbols! { infer_outlives_requirements, infer_static_outlives_requirements, inherent_associated_types, - inherent_str_constructors, inherit, inlateout, inline, diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index bc33affb3a15c..730cafa8a0543 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,6 +82,7 @@ use crate::ptr; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { str::from_utf8(v) } @@ -118,15 +119,9 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - // FIXME(const-hack): This should use `?` again, once it's `const` - match super::run_utf8_validation(v) { - Ok(_) => { - // SAFETY: validation succeeded. - Ok(unsafe { str::from_utf8_unchecked_mut(v) }) - } - Err(err) => Err(err), - } + str::from_utf8_mut(v) } /// Converts a slice of bytes to a string slice without checking @@ -158,6 +153,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: same requirements unsafe { str::from_utf8_unchecked(v) } @@ -184,6 +180,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked_mut", since = "1.83.0")] +#[rustc_diagnostic_item = "from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: same requirements unsafe { str::from_utf8_unchecked_mut(v) } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index f9b78e89d655f..4263f4223bceb 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -233,9 +233,7 @@ impl str { /// assert_eq!("💖", sparkle_heart); /// ``` #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] #[rustc_allow_const_fn_unstable(str_internals)] - #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -278,8 +276,6 @@ impl str { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -319,8 +315,6 @@ impl str { #[inline] #[must_use] #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -347,8 +341,6 @@ impl str { #[inline] #[must_use] #[unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_const_unstable(feature = "inherent_str_constructors", issue = "131114")] - #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs deleted file mode 100644 index fb76e9628ac74..0000000000000 --- a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Test that inherent str constructors cannot be used when inherent_str_constructors -// feature gate is not used. - -fn main() { - str::from_utf8(b"hi").unwrap(); -} diff --git a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr b/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr deleted file mode 100644 index bccbf11f1b9be..0000000000000 --- a/tests/ui/feature-gates/feature-gate-inherent-str-constructors.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope - --> $DIR/feature-gate-inherent-str-constructors.rs:5:10 - | -LL | str::from_utf8(b"hi").unwrap(); - | ^^^^^^^^^ function or associated item not found in `str` - | -help: you are looking for the module in `std`, not the primitive type - | -LL | std::str::from_utf8(b"hi").unwrap(); - | +++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`.