<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Wed, 29 Aug 2018 at 01:38, Stephan Bergmann via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Given code like<br>
<br>
   struct S1 { S1(S1 &&); };<br>
   struct S2: S1 {};<br>
   S1 f(S2 s) { return s; }<br>
<br>
and the rules for when s in the return statement is treated like an <br>
rvalue when picking the ctor to use ([class.copy.elision]/3 in C++17, <br>
[class.copy]/32 in C++14, and [class.copy]/32 plus CWG1579 in C++11), my <br>
interpretation is that the code is correct and should pick the S1 move ctor.<br>
<br>
However, any version of Clang up to recent trunk rejects the code, <br>
trying to call the implicitly deleted S1 copy ctor.  GCC >= 8.1 accepts <br>
the code, and I wonder whether Clang or GCC (and my interpretation) is <br>
wrong.<br></blockquote><div><br></div><div>GCC does not implement one part of the relevant language rule. Specifically, the rule is ([class.copy.elision]p3):</div><div><br></div><div>  "[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]"</div><div><br></div><div>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.</div><div><br></div><div>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.</div></div></div>