The following code is rejected by both Clang and GCC (trunk versions):
#include <memory>
struct Base
{
Base() = default;
Base(Base const&) = delete;
Base(Base&&) = default;
};
struct Derived : Base
{
Derived() = default;
Derived(Derived const&) = delete;
Derived(Derived&&) = default;
};
auto foo()
-> Base
{
Derived d;
return d; // ERROR HERE
}
Causing the following error:
prog.cc: In function 'Base foo()': prog.cc:21:12: error: use of deleted function 'Base::Base(const Base&)'
return d;
^
According to [class.copy]/32:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue
If the sentence above is meant to be parsed as (copy elision criteria met && lvalue) || (id-expression designating an automatic object)
, as this CWG defect seems to indicate, why isn't the last condition applying here? Is there a compiler bug both in Clang and GCC?
On the other hand, if the sentence is meant to be parsed as (copy elision criteria met && (lvalue || id-expression designating an automatic object))
, isn't this a very misleading wording worth a DR?
[class.copy]/32 continues:
The first overload resolution, treating
d
as an rvalue, selectsBase::Base(Base&&)
. The type of the first parameter of the selected constructor is, however, notDerived&&
butBase&&
, so the result of that overload resolution is discarded and you perform overload resolution again, treatingd
as an lvalue. That second overload resolution selects the deleted copy constructor.