Description
I don't know if it is really worth looking into, but I think I found some weird behavior in the rust compiler:
Let's consider the two following functions (godbolt link):
pub fn nop(a: &String) {
a.as_str().to_owned();
}
pub fn complex(a: &String) {
a.to_owned();
}
They both allocate a String struct but do not use or return it. Rustc is able to optimize away the first one, but not the second one.
If we dig deeper, we can observe that the compiler is not able to optimize away the to_owned
and clone
method when called on a string. Let's look at the following functions (godbolt link):
pub fn a() {
"ok".to_owned();
}
pub fn b() {
"ok".to_owned().clone();
}
pub fn c() {
"ok".to_owned().as_str().to_owned();
}
pub fn d() {
"ok".to_owned().to_owned();
}
pub fn e() {
String::from("ok");
}
The fonctions a
, c
and e
are optimized away even on opt-level 2. Whereas the functions b
and d
are not and still produce calls to alloc
, dealloc
, drop_in_place
, etc...
Looking at the stdlib code, <&str>::to_owned
internally calls <&[u8]>::to_owned
, which calls <&[u8]>::to_vec
, which calls <&[u8]>::to_vec_in
which ends up calling hack::to_vec
.
String::to_string
calls String::to_owned
which calls String::clone
which calls Vec<u8>::clone
which calls <&[u8]>::to_vec_in
with the only difference from the <&str>::to_owned
path being that the possibly custom allocator of the Vec
internal buffer is cloned and passed to <&[u8]>::to_vec_in
in Vec<u8>::clone
.
Is it possible that rustc is not able to correctly inline the allocator functions when the default allocator is not directly assumed ?
This was tested on Rustc 1.55
and `Rustc 1.57.0-nightly (b69fe57 2021-09-10)
This issue has been assigned to @notriddle via this comment.