I’m curious as to exactly how this feature works. Consider something like
std::unique_ptr<int> f() { std::unique_ptr<int> lval(nullptr); return lval; }
This code compiles fine even for a move-only type, as the compiler implicitly moves it. But logically, for any return expression, determining whether or not the result refers to a local variable would be solving the Halting Problem- and if the compiler simply treated all local variables as rvalues in the return expression, then this would be problematic as the variable may be referred to in that one expression multiple times. Even if a local only had one direct reference, you would not be able to prove that it did not have other indirect aliases.
So how does the compiler know when to move from the return expression?
There’s a simple rule: If the conditions for copy elision are met (except that the variable may be function parameter), treat as rvalue. If that fails, treat as lvalue. Otherwise, treat as lvalue.
§12.8 [class.copy] p32Example:
Not that I personally agree with that rule, since there is no automatic move in the following code:
See also this question of mine.