Search code examples
c++c++17language-lawyermove-semanticsxvalue

Validity of presenting an xvalue as an lvalue


The following function (in my intention) is to take an rvalue and present it as it was an lvalue.

auto constexpr RtoL = [](auto&& r) -> decltype(auto) {
    static_assert(std::is_rvalue_reference_v<decltype(r)>, "Gimme rvalues, not lvalues.");
    return (r);
};

I think of using it in situations where I can guarantee that an xvalue has not been truly moved from (e.g. it was casted to rvalue via std::move, but nothing took advantage of that), so I'd call it with xvalues, not prvalues.

Anyway, compilers (well, versions of GCC) seem to have different opinions on the validity of the code above. Specifically, given this usage:

int main() {
    int x{3};
    RtoL(std::move(x));
}

GCC 11.2 considers it invalid:

<source>:9:14: error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'
    9 |     return (r);
      |              ^

whereas GCC 10.3 and other compilers consider it valid.

Furthermore, changing the return statement from

return (r);

to

return static_cast<decltype(r)&>(r);

makes them all agree that the code is correct.

Where is the truth, from the standard standpoint?


Solution

  • This was a bug in past versions of GCC (located by commenter @Enlico)

    The bug is fixed by GCC version 12.2, but still manifests with GCC 11.3. It will likely be fixed in GCC 11.4 as well.

    See this on GodBolt.