https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789
--- Comment #10 from Arthur O'Dwyer <arthur.j.odwyer at gmail dot com> --- FWIW, I think I agree with your analysis. To reiterate what you already said (and I think GCC already gets the following snippet correct): in X g (X x) try { throw x; } catch (...) { return x; } the `throw x` copies but the `return x` moves. That is, `throw x` treats `x` as an lvalue because it could be used again later (in the function-catch-block), but `return x` treats it as an rvalue because it can't[*] be used again later. [* — except if you sneakily use a captured reference within a destructor, but C++ implicit move doesn't care — has never cared — about such sneaky uses]