Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alloc: add ToString specialization for &&str #128759

Merged
merged 4 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2643,14 +2643,41 @@ impl ToString for i8 {
}
}

#[doc(hidden)]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
impl ToString for str {
#[inline]
fn to_string(&self) -> String {
String::from(self)
}
// Generic/generated code can sometimes have multiple, nested references
// for strings, including `&&&str`s that would never be written
// by hand. This macro generates twelve layers of nested `&`-impl
// for primitive strings.
macro_rules! to_string_str {
{type ; x $($x:ident)*} => {
&to_string_str! { type ; $($x)* }
};
{type ;} => { str };
notriddle marked this conversation as resolved.
Show resolved Hide resolved
{impl ; x $($x:ident)*} => {
to_string_str! { $($x)* }
};
{impl ;} => { };
{$self:expr ; x $($x:ident)*} => {
*(to_string_str! { $self ; $($x)* })
};
{$self:expr ;} => { $self };
notriddle marked this conversation as resolved.
Show resolved Hide resolved
{$($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)* }
};
notriddle marked this conversation as resolved.
Show resolved Hide resolved
}
notriddle marked this conversation as resolved.
Show resolved Hide resolved

to_string_str! {
x x x x
x x x x
x x x x
}

#[doc(hidden)]
Expand Down
36 changes: 36 additions & 0 deletions tests/codegen/issues/str-to-string-128690.rs
Original file line number Diff line number Diff line change
@@ -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()
}
Loading