N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter, which is written to before returning. If you're returning a newly-constructed object, the compiler can rewrite that into calling the constructor on the pointer, but if you're returning a named object, the class may have a non-trivial destructor that needs to run after the move, such that it's not possible to rewrite uses of the local object into uses of the pointer.
I'm not too confident on that last part, because such an implementation would mess with semantics in case of an exception, so anyone feel free to correct me on that.
I'm not too confident on that last part, because such an implementation would mess with semantics in case of an exception, so anyone feel free to correct me on that.