alloc: add ToString specialization for &&str

Fixes #128690
This commit is contained in:
Michael Howell 2024-08-06 14:33:14 -07:00
parent 83e9b93c90
commit 1b587a6e76
2 changed files with 71 additions and 8 deletions

View File

@ -2643,14 +2643,41 @@ fn to_string(&self) -> String {
} }
} }
#[doc(hidden)] // Generic/generated code can sometimes have multiple, nested references
#[cfg(not(no_global_oom_handling))] // for strings, including `&&&str`s that would never be written
#[stable(feature = "str_to_string_specialization", since = "1.9.0")] // by hand. This macro generates twelve layers of nested `&`-impl
impl ToString for str { // for primitive strings.
#[inline] macro_rules! to_string_str {
fn to_string(&self) -> String { {type ; x $($x:ident)*} => {
String::from(self) &to_string_str! { type ; $($x)* }
} };
{type ;} => { str };
{impl ; x $($x:ident)*} => {
to_string_str! { $($x)* }
};
{impl ;} => { };
{$self:expr ; x $($x:ident)*} => {
*(to_string_str! { $self ; $($x)* })
};
{$self:expr ;} => { $self };
{$($x:ident)*} => {
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
impl ToString for to_string_str!(type ; $($x)*) {
#[inline]
fn to_string(&self) -> String {
String::from(to_string_str!(self ; $($x)*))
}
}
to_string_str! { impl ; $($x)* }
};
}
to_string_str! {
x x x x
x x x x
x x x x
} }
#[doc(hidden)] #[doc(hidden)]

View File

@ -0,0 +1,36 @@
//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
#![crate_type = "lib"]
//! Make sure str::to_string is specialized not to use fmt machinery.
// CHECK-LABEL: define {{(dso_local )?}}void @one_ref
#[no_mangle]
pub fn one_ref(input: &str) -> String {
// CHECK-NOT: {{(call|invoke).*}}fmt
input.to_string()
}
// CHECK-LABEL: define {{(dso_local )?}}void @two_ref
#[no_mangle]
pub fn two_ref(input: &&str) -> String {
// CHECK-NOT: {{(call|invoke).*}}fmt
input.to_string()
}
// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
#[no_mangle]
pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
// CHECK-NOT: {{(call|invoke).*}}fmt
input.to_string()
}
// This is a known performance cliff because of the macro-generated
// specialized impl. If this test suddenly starts failing,
// consider removing the `to_string_str!` macro in `alloc/str/string.rs`.
//
// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
#[no_mangle]
pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
// CHECK: {{(call|invoke).*}}fmt
input.to_string()
}