I thought that once an object is moved, the memory occupied by it on the stack can be reused for other purpose. However, the minimal example below shows the opposite.
#[inline(never)] fn consume_string(s: String) { drop(s); } fn main() { println!( "String occupies {} bytes on the stack.", std::mem::size_of::<String>() ); let s = String::from("hello"); println!("s at {:p}", &s); consume_string(s); let r = String::from("world"); println!("r at {:p}", &r); consume_string(r); } After compiling the code with --release flag, it gives the following output on my computer.
String occupies 24 bytes on the stack. s at 0x7ffee3b011b0 r at 0x7ffee3b011c8 It is pretty clear that even if s is moved, r does not reuse the 24-byte chunk on the stack that originally belonged to s. I suppose that reusing the stack memory of a moved object is safe, but why does the Rust compiler not do it? Am I missing any corner case?
Update: If I enclose s by curly brackets, r can reuse the 24-byte chunk on the stack.
#[inline(never)] fn consume_string(s: String) { drop(s); } fn main() { println!( "String occupies {} bytes on the stack.", std::mem::size_of::<String>() ); { let s = String::from("hello"); println!("s at {:p}", &s); consume_string(s); } let r = String::from("world"); println!("r at {:p}", &r); consume_string(r); } The code above gives the output below.
String occupies 24 bytes on the stack. s at 0x7ffee2ca31f8 r at 0x7ffee2ca31f8 I thought that the curly brackets should not make any difference, because the lifetime of s ends after calling comsume_string(s) and its drop handler is called within comsume_string(). Why does adding the curly brackets enable the optimization?
The version of the Rust compiler I am using is given below.
rustc 1.54.0-nightly (5c0292654 2021-05-11) binary: rustc commit-hash: 5c029265465301fe9cb3960ce2a5da6c99b8dcf2 commit-date: 2021-05-11 host: x86_64-apple-darwin release: 1.54.0-nightly LLVM version: 12.0.1 Update 2: I would like to clarify my focus of this question. I want to know the proposed "stack reuse optimization" lies in which category.
- This is an invalid optimization. Under certain cases the compiled code may fail if we perform the "optimization".
- This is a valid optimization, but the compiler (including both rustc frontend and llvm) is not capable of performing it.
- This is a valid optimization, but is temporarily turned off, like this.
- This is a valid optimization, but is missed. It will be added in the future.
.push_str()forces the String instances to occupy space on the stack (2) no observable behavior is altered because nothing is observable (3) the space is not reused aftersends its lifetime