Closed
Description
Sometimes boxing a generated Future causes the value to be (unnecessarily?) copied. This can be worked around by wrapping the call to Box::new
.
Code:
use std::future::ready;
use std::mem;
struct Foo {}
impl Drop for Foo {
fn drop(&mut self) {
println!("foo");
}
}
async fn func1() {
let _f = Foo {};
let mut buf = [0u8; 16_384];
buf[0] = 42;
ready(()).await;
println!("{}", buf[0]);
}
fn _box_new<T>(x: T) -> Box<T> {
Box::new(x)
}
fn take<T>(v: T) {
println!("{}", mem::size_of_val(&v));
}
fn main() {
take(Box::new(func1()));
//take(_box_new(func1()));
}
Asm contains a ~16k memcpy:
$ rustc -O --edition 2021 --emit asm boxcopybug.rs && grep -B 3 memcpy boxcopybug.s
leaq 32(%rsp), %rsi
movl $16386, %edx
movq %rax, %rdi
callq *memcpy@GOTPCREL(%rip)
In main, if you comment out the first line and uncomment the second, the memcpy goes away, even though the code is nearly identical. I'd expect both ways to compile down the same.
Box::pin
is similarly affected.
The behavior is present in the latest stable and nightly.
rustc --version --verbose
:
rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: x86_64-unknown-linux-gnu
release: 1.63.0
LLVM version: 14.0.5