It's quite simple.
return buffer;
If you do this, then either NRVO will happen or it won't. If it doesn't happen then buffer will be moved from.
return std::move( buffer );
If you do this, then NVRO will not happen, and buffer will be moved from.
So there is nothing to gain by using std::move here, and much to lose.
There is one exception to this rule:
Buffer read(Buffer&& buffer) {
//...
return std::move( buffer );
}
If buffer is an rvalue reference, then you should use std::move. This is because references are not eligible for NRVO, so without std::move it would result in a copy from an lvalue.
This is just an instance of the rule "always move rvalue references and forward universal references", which takes precedence over the rule "never move a return value".