It's a little more subtle than that. "val" is definitely an lvalue. However, when returning a local variable like this, C++11 has a rule: "if the NRVO activates, there are no copies/moves. Otherwise, see if you can treat val as an rvalue - if so, you get a move. That almost always works, but if it doesn't, fall back to treating it as an lvalue so it compiles with a copy like it used to."
This is the one time in the language that lvalues are automatically moved from, and it's because the language/compiler knows that returning from a function will destroy all local variables, so it's safe to move from them.