Don't return a `T&&`
Reason
It's asking to return a reference to a destroyed temporary object. An && is a magnet for temporary objects.
Example
A returned rvalue reference goes out of scope at the end of the full expression to which it is returned:
auto&& x = max(0, 1); // OK, so far
foo(x); // Undefined behavior
This kind of use is a frequent source of bugs, often incorrectly reported as a compiler bug. An implementer of a function should avoid setting such traps for users.
The lifetime safety profile will (when completely implemented) catch such problems.
Example
Returning an rvalue reference is fine when the reference to the temporary is being passed "downward" to a callee; then, the temporary is guaranteed to outlive the function call (see F.18 and F.19). However, it's not fine when passing such a reference "upward" to a larger caller scope. For passthrough functions that pass in parameters (by ordinary reference or by perfect forwarding) and want to return values, use simple auto return type deduction (not auto&&).
Assume that F returns by value:
template<class F>
auto&& wrapper(F f)
{
log_call(typeid(f)); // or whatever instrumentation
return f(); // BAD: returns a reference to a temporary
}
Better:
template<class F>
auto wrapper(F f)
{
log_call(typeid(f)); // or whatever instrumentation
return f(); // OK
}
Exception
std::move and std::forward do return &&, but they are just casts -- used by convention only in expression contexts where a reference to a temporary object is passed along within the same expression before the temporary is destroyed. We don't know of any other good examples of returning &&.
Enforcement
Flag any use of && as a return type, except in std::move and std::forward.