Does Rust have return value optimization?

Am I correct thinking that a function returning a large struct is not going to actually cause a memcpy of the struct?
i.e. fn foo() -> BigStruct is going to be optimized to be something like fn foo(ret: *mut BigStruct).

If it does, is it just LLVM optimization (that may or may not be applied), or part of the current Rust ABI?

5 Likes

AFAIK, it's just like (current) C++ in this regard - it's an optimization, without any guarantees that it'll happen. Not sure if that will change with MIR maturing and rust doing its own pre-LLVM optimizations.

1 Like

The first edition of the book has a section that talks about returning large structs and immediately boxing them up. This is about functions with signatures like

fn foo() -> Box<BigStruct>

and the advice there is to simply return the BigStruct directly and let the caller decide what to do with it:

let boxed: Boxed<BigStruct> = box foo();

The book says there will be no copying done in this case. Unfortunately the book doesn't go into any detail about this pattern and it's not clear to me either when one can rely on this optimization.

It also doesn't say anything about the unboxed case, i.e., your case with code like this:

let unboxed: BigStruct = foo();
1 Like

box foo() is not an example of RVO; it's more like "placement new" in C++ - the result is written directly into the allocated memory, rather than copied from the stack first.

As of the 2017 standard, C++ does guarantee copy-elision, including RVO.

4 Likes

Yeah, I knew they were considering it, but wasn't sure which version it'll make - hence the "(current)" caveat in my reply. Thanks for mentioning it's C++17.

Is it possible to make such RVO a guarantee for Rust compiler(s)?

1 Like

Follow along in Do move forwarding on MIR · Issue #32966 · rust-lang/rust · GitHub.

4 Likes