[cfe-dev] return lvalue move instead of copy?

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Wed Aug 29 15:06:00 PDT 2018


On Wed, 29 Aug 2018 at 01:38, Stephan Bergmann via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Given code like
>
>    struct S1 { S1(S1 &&); };
>    struct S2: S1 {};
>    S1 f(S2 s) { return s; }
>
> and the rules for when s in the return statement is treated like an
> rvalue when picking the ctor to use ([class.copy.elision]/3 in C++17,
> [class.copy]/32 in C++14, and [class.copy]/32 plus CWG1579 in C++11), my
> interpretation is that the code is correct and should pick the S1 move
> ctor.
>
> However, any version of Clang up to recent trunk rejects the code,
> trying to call the implicitly deleted S1 copy ctor.  GCC >= 8.1 accepts
> the code, and I wonder whether Clang or GCC (and my interpretation) is
> wrong.
>

GCC does not implement one part of the relevant language rule.
Specifically, the rule is ([class.copy.elision]p3):

  "[After performing overload resolution for an implicit move from an
rvalue,] if the type of the first parameter of the selected constructor is
not an rvalue reference to the object's type (possibly-cv-qualified), [a
copy is used instead of a move]"

In your example, the selected constructor is the S1 move constructor, whose
parameter type (S1&&) is not an rvalue reference to S2. So a copy is
performed instead of a move.

This rule makes some amount of sense: you may not want to "slice out" the
base class of an object by move, because that would leave the derived class
object in a half-unspecified state (the derived portion would be in its
original state but the base class subobject would be in a moved-from
state), which could break the class's invariants and cause the derived
object's destructor to fail.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180829/e60f7936/attachment.html>


More information about the cfe-dev mailing list