r193969 - Implement final resolution of DR1402: implicitly-declared move operators that
Richard Smith
richard-llvm at metafoo.co.uk
Sun Nov 3 17:48:18 PST 2013
Author: rsmith
Date: Sun Nov 3 19:48:18 2013
New Revision: 193969
URL: http://llvm.org/viewvc/llvm-project?rev=193969&view=rev
Log:
Implement final resolution of DR1402: implicitly-declared move operators that
would be deleted are still declared, but are ignored by overload resolution.
Also, don't delete such members if a subobject has no corresponding move
operation and a non-trivial copy. This causes us to implicitly declare move
operations in more cases, but risks move-assigning virtual bases multiple
times in some circumstances (a warning for that is to follow).
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTWriter.cpp
cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
cfe/trunk/test/CXX/drs/dr1xx.cpp
cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp
cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sun Nov 3 19:48:18 2013
@@ -444,14 +444,6 @@ class CXXRecordDecl : public RecordDecl
/// const-qualified reference parameter or a non-reference parameter.
bool HasDeclaredCopyAssignmentWithConstParam : 1;
- /// \brief Whether an implicit move constructor was attempted to be declared
- /// but would have been deleted.
- bool FailedImplicitMoveConstructor : 1;
-
- /// \brief Whether an implicit move assignment operator was attempted to be
- /// declared but would have been deleted.
- bool FailedImplicitMoveAssignment : 1;
-
/// \brief Whether this class describes a C++ lambda.
bool IsLambda : 1;
@@ -773,12 +765,14 @@ public:
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move constructor that is not deleted.
bool hasSimpleMoveConstructor() const {
- return !hasUserDeclaredMoveConstructor() && hasMoveConstructor();
+ return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&
+ !data().DefaultedMoveConstructorIsDeleted;
}
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move assignment operator that is not deleted.
bool hasSimpleMoveAssignment() const {
- return !hasUserDeclaredMoveAssignment() && hasMoveAssignment();
+ return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
+ !data().DefaultedMoveAssignmentIsDeleted;
}
/// \brief \c true if we know for sure that this class has an accessible
/// destructor that is not deleted.
@@ -870,28 +864,23 @@ public:
needsImplicitMoveConstructor();
}
- /// \brief Determine whether implicit move constructor generation for this
- /// class has failed before.
- bool hasFailedImplicitMoveConstructor() const {
- return data().FailedImplicitMoveConstructor;
- }
-
- /// \brief Set whether implicit move constructor generation for this class
- /// has failed before.
- void setFailedImplicitMoveConstructor(bool Failed = true) {
- data().FailedImplicitMoveConstructor = Failed;
+ /// \brief Set that we attempted to declare an implicitly move
+ /// constructor, but overload resolution failed so we deleted it.
+ void setImplicitMoveConstructorIsDeleted() {
+ assert((data().DefaultedMoveConstructorIsDeleted ||
+ needsOverloadResolutionForMoveConstructor()) &&
+ "move constructor should not be deleted");
+ data().DefaultedMoveConstructorIsDeleted = true;
}
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
bool needsImplicitMoveConstructor() const {
- return !hasFailedImplicitMoveConstructor() &&
- !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
+ return !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveAssignment() &&
- !hasUserDeclaredDestructor() &&
- !data().DefaultedMoveConstructorIsDeleted;
+ !hasUserDeclaredDestructor();
}
/// \brief Determine whether we need to eagerly declare a defaulted move
@@ -947,29 +936,24 @@ public:
needsImplicitMoveAssignment();
}
- /// \brief Determine whether implicit move assignment generation for this
- /// class has failed before.
- bool hasFailedImplicitMoveAssignment() const {
- return data().FailedImplicitMoveAssignment;
- }
-
- /// \brief Set whether implicit move assignment generation for this class
- /// has failed before.
- void setFailedImplicitMoveAssignment(bool Failed = true) {
- data().FailedImplicitMoveAssignment = Failed;
+ /// \brief Set that we attempted to declare an implicit move assignment
+ /// operator, but overload resolution failed so we deleted it.
+ void setImplicitMoveAssignmentIsDeleted() {
+ assert((data().DefaultedMoveAssignmentIsDeleted ||
+ needsOverloadResolutionForMoveAssignment()) &&
+ "move assignment should not be deleted");
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
/// \brief Determine whether this class should get an implicit move
/// assignment operator or if any existing special member function inhibits
/// this.
bool needsImplicitMoveAssignment() const {
- return !hasFailedImplicitMoveAssignment() &&
- !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
+ return !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveConstructor() &&
- !hasUserDeclaredDestructor() &&
- !data().DefaultedMoveAssignmentIsDeleted;
+ !hasUserDeclaredDestructor();
}
/// \brief Determine whether we need to eagerly declare a move assignment
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sun Nov 3 19:48:18 2013
@@ -1983,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(R
= FromData.HasDeclaredCopyConstructorWithConstParam;
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
- ToData.FailedImplicitMoveConstructor
- = FromData.FailedImplicitMoveConstructor;
- ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Nov 3 19:48:18 2013
@@ -71,7 +71,6 @@ CXXRecordDecl::DefinitionData::Definitio
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
Definition(D), FirstFriend() {
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Nov 3 19:48:18 2013
@@ -9231,11 +9231,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopy
? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
: ClassDecl->hasTrivialCopyAssignment());
- // C++11 [class.copy]p19:
- // .... If the class definition does not explicitly declare a copy
- // assignment operator, there is no user-declared move constructor, and
- // there is no user-declared move assignment operator, a copy assignment
- // operator is implicitly declared as defaulted.
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
SetDeclDeleted(CopyAssignment, ClassLoc);
@@ -9572,120 +9567,13 @@ Sema::ComputeDefaultedMoveAssignmentExce
return ExceptSpec;
}
-/// Determine whether the class type has any direct or indirect virtual base
-/// classes which have a non-trivial move assignment operator.
-static bool
-hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- CXXRecordDecl *BaseClass =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- // Try to declare the move assignment. If it would be deleted, then the
- // class does not have a non-trivial move assignment.
- if (BaseClass->needsImplicitMoveAssignment())
- S.DeclareImplicitMoveAssignment(BaseClass);
-
- if (BaseClass->hasNonTrivialMoveAssignment())
- return true;
- }
-
- return false;
-}
-
-/// Determine whether the given type either has a move constructor or is
-/// trivially copyable.
-static bool
-hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
- Type = S.Context.getBaseElementType(Type);
-
- // FIXME: Technically, non-trivially-copyable non-class types, such as
- // reference types, are supposed to return false here, but that appears
- // to be a standard defect.
- CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl || !ClassDecl->getDefinition() || ClassDecl->isInvalidDecl())
- return true;
-
- if (Type.isTriviallyCopyableType(S.Context))
- return true;
-
- if (IsConstructor) {
- // FIXME: Need this because otherwise hasMoveConstructor isn't guaranteed to
- // give the right answer.
- if (ClassDecl->needsImplicitMoveConstructor())
- S.DeclareImplicitMoveConstructor(ClassDecl);
- return ClassDecl->hasMoveConstructor();
- }
-
- // FIXME: Need this because otherwise hasMoveAssignment isn't guaranteed to
- // give the right answer.
- if (ClassDecl->needsImplicitMoveAssignment())
- S.DeclareImplicitMoveAssignment(ClassDecl);
- return ClassDecl->hasMoveAssignment();
-}
-
-/// Determine whether all non-static data members and direct or virtual bases
-/// of class \p ClassDecl have either a move operation, or are trivially
-/// copyable.
-static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl,
- bool IsConstructor) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- if (Base->isVirtual())
- continue;
-
- if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
- return false;
- }
-
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
- return false;
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(), IsConstructor))
- return false;
- }
-
- return true;
-}
-
CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
- // C++11 [class.copy]p20:
- // If the definition of a class X does not explicitly declare a move
- // assignment operator, one will be implicitly declared as defaulted
- // if and only if:
- //
- // - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveAssignment());
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
if (DSM.isAlreadyBeingDeclared())
return 0;
- // [Checked after we build the declaration]
- // - the move assignment operator would not be implicitly defined as
- // deleted,
-
- // [DR1402]:
- // - X has no direct or indirect virtual base class with a non-trivial
- // move assignment operator, and
- // - each of X's non-static data members and direct or virtual base classes
- // has a type that either has a move assignment operator or is trivially
- // copyable.
- if (hasVirtualBaseWithNonTrivialMoveAssignment(*this, ClassDecl) ||
- !subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl,/*Constructor*/false)) {
- ClassDecl->setFailedImplicitMoveAssignment();
- return 0;
- }
-
// Note: The following rules are largely analoguous to the move
// constructor rules.
@@ -9729,18 +9617,9 @@ CXXMethodDecl *Sema::DeclareImplicitMove
? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
: ClassDecl->hasTrivialMoveAssignment());
- // C++0x [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // assignment operator, one will be implicitly declared as defaulted if and
- // only if:
- // [...]
- // - the move assignment operator would not be implicitly defined as
- // deleted.
if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
- // Cache this result so that we don't try to generate this over and over
- // on every lookup, leaking memory and wasting time.
- ClassDecl->setFailedImplicitMoveAssignment();
- return 0;
+ ClassDecl->setImplicitMoveAssignmentIsDeleted();
+ SetDeclDeleted(MoveAssignment, ClassLoc);
}
// Note that we have added this copy-assignment operator.
@@ -9782,6 +9661,17 @@ void Sema::DefineImplicitMoveAssignment(
// are assigned, in the order in which they were declared in the class
// definition.
+ // FIXME: Issue a warning if our implicit move assignment operator will move
+ // from a virtual base more than once. For instance, given:
+ //
+ // struct A { A &operator=(A&&); };
+ // struct B : virtual A {};
+ // struct C : virtual A {};
+ // struct D : B, C {};
+ //
+ // If the move assignment operator of D is synthesized, we should warn,
+ // because the A vbase will be moved from multiple times.
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
@@ -10071,11 +9961,6 @@ CXXConstructorDecl *Sema::DeclareImplici
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
: ClassDecl->hasTrivialCopyConstructor());
- // C++11 [class.copy]p8:
- // ... If the class definition does not explicitly declare a copy
- // constructor, there is no user-declared move constructor, and there is no
- // user-declared move assignment operator, a copy constructor is implicitly
- // declared as defaulted.
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
SetDeclDeleted(CopyConstructor, ClassLoc);
@@ -10195,29 +10080,12 @@ Sema::ComputeDefaultedMoveCtorExceptionS
CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
CXXRecordDecl *ClassDecl) {
- // C++11 [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // constructor, one will be implicitly declared as defaulted if and only if:
- //
- // - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveConstructor());
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
if (DSM.isAlreadyBeingDeclared())
return 0;
- // [Checked after we build the declaration]
- // - the move assignment operator would not be implicitly defined as
- // deleted,
-
- // [DR1402]:
- // - each of X's non-static data members and direct or virtual base classes
- // has a type that either has a move constructor or is trivially copyable.
- if (!subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl, /*Constructor*/true)) {
- ClassDecl->setFailedImplicitMoveConstructor();
- return 0;
- }
-
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = Context.getRValueReferenceType(ClassType);
@@ -10260,16 +10128,9 @@ CXXConstructorDecl *Sema::DeclareImplici
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
: ClassDecl->hasTrivialMoveConstructor());
- // C++0x [class.copy]p9:
- // If the definition of a class X does not explicitly declare a move
- // constructor, one will be implicitly declared as defaulted if and only if:
- // [...]
- // - the move constructor would not be implicitly defined as deleted.
if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
- // Cache this result so that we don't try to generate this over and over
- // on every lookup, leaking memory and wasting time.
- ClassDecl->setFailedImplicitMoveConstructor();
- return 0;
+ ClassDecl->setImplicitMoveConstructorIsDeleted();
+ SetDeclDeleted(MoveConstructor, ClassLoc);
}
// Note that we have declared this constructor.
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Nov 3 19:48:18 2013
@@ -3602,8 +3602,8 @@ static bool evaluateTypeTrait(Sema &S, T
// is_trivially_constructible is defined as:
//
// is_constructible<T, Args...>::value is true and the variable
- // definition for is_constructible, as defined below, is known to call no
- // operation that is not trivial.
+ // definition for is_constructible, as defined below, is known to call
+ // no operation that is not trivial.
//
// The predicate condition for a template specialization
// is_constructible<T, Args...> shall be satisfied if and only if the
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Nov 3 19:48:18 2013
@@ -5448,10 +5448,18 @@ Sema::AddOverloadCandidate(FunctionDecl
if (!CandidateSet.isNewCandidate(Function))
return;
+ // C++11 [class.copy]p11: [DR1402]
+ // A defaulted move constructor that is defined as deleted is ignored by
+ // overload resolution.
+ CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function);
+ if (Constructor && Constructor->isDefaulted() && Constructor->isDeleted() &&
+ Constructor->isMoveConstructor())
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){
+ if (Constructor) {
// C++ [class.copy]p3:
// A member function template is never instantiated to perform the copy
// of a class object to an object of its class type.
@@ -5626,6 +5634,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *
if (!CandidateSet.isNewCandidate(Method))
return;
+ // C++11 [class.copy]p23: [DR1402]
+ // A defaulted move assignment operator that is defined as deleted is
+ // ignored by overload resolution.
+ if (Method->isDefaulted() && Method->isDeleted() &&
+ Method->isMoveAssignmentOperator())
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sun Nov 3 19:48:18 2013
@@ -1208,8 +1208,6 @@ void ASTDeclReader::ReadCXXDefinitionDat
Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
- Data.FailedImplicitMoveConstructor = Record[Idx++];
- Data.FailedImplicitMoveAssignment = Record[Idx++];
Data.NumBases = Record[Idx++];
if (Data.NumBases)
Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sun Nov 3 19:48:18 2013
@@ -5106,8 +5106,6 @@ void ASTWriter::AddCXXDefinitionData(con
Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
- Record.push_back(Data.FailedImplicitMoveConstructor);
- Record.push_back(Data.FailedImplicitMoveAssignment);
// IsLambda bit is already saved.
Record.push_back(Data.NumBases);
Modified: cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp (original)
+++ cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp Sun Nov 3 19:48:18 2013
@@ -22,7 +22,7 @@ struct H;
struct D {
virtual E &operator=(const E &); // expected-note {{here}}
virtual F &operator=(const F &);
- virtual G &operator=(G&&);
+ virtual G &operator=(G&&); // expected-note {{here}}
virtual H &operator=(H&&); // expected-note {{here}}
friend struct F;
@@ -34,8 +34,8 @@ private:
struct E : D {}; // expected-error {{deleted function '~E' cannot override a non-deleted function}} \
// expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
struct F : D {};
-// No move ctor here, because it would be deleted.
struct G : D {}; // expected-error {{deleted function '~G' cannot override a non-deleted function}}
+ // expected-error at -1 {{deleted function 'operator=' cannot override a non-deleted function}}
struct H : D {
H &operator=(H&&) = default; // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
~H();
Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr1xx.cpp Sun Nov 3 19:48:18 2013
@@ -71,7 +71,7 @@ namespace dr109 { // dr109: yes
namespace dr111 { // dr111: dup 535
struct A { A(); A(volatile A&, int = 0); A(A&, const char * = "foo"); };
- struct B : A { B(); }; // expected-note {{would lose const qualifier}} expected-note {{requires 0 arguments}}
+ struct B : A { B(); }; // expected-note +{{would lose const qualifier}} expected-note {{requires 0 arguments}}
const B b1;
B b2(b1); // expected-error {{no matching constructor}}
}
Modified: cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp Sun Nov 3 19:48:18 2013
@@ -190,49 +190,59 @@ namespace DR1402 {
NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default;
};
- // A non-movable, non-trivially-copyable class type as a subobject inhibits
- // the declaration of a move operation.
- struct NoMove1 { NonTrivialCopyCtor ntcc; }; // expected-note 2{{'const DR1402::NoMove1 &'}}
- struct NoMove2 { NonTrivialCopyAssign ntcc; }; // expected-note 2{{'const DR1402::NoMove2 &'}}
- struct NoMove3 : NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove3 &'}}
- struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove4 &'}}
- struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove5 &'}}
- struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove6 &'}}
- struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'const DR1402::NoMove7 &'}}
- struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'const DR1402::NoMove8 &'}}
+ // DR1402: A non-movable, non-trivially-copyable class type as a subobject no
+ // longer inhibits the declaration of a move operation.
+ struct NoMove1 { NonTrivialCopyCtor ntcc; };
+ struct NoMove2 { NonTrivialCopyAssign ntcc; };
+ struct NoMove3 : NonTrivialCopyCtor {};
+ struct NoMove4 : NonTrivialCopyAssign {};
+ struct NoMove5 : virtual NonTrivialCopyCtor {};
+ struct NoMove6 : virtual NonTrivialCopyAssign {};
+ struct NoMove7 : NonTrivialCopyCtorVBase {};
+ struct NoMove8 : NonTrivialCopyAssignVBase {};
- // A non-trivially-move-assignable virtual base class inhibits the declaration
- // of a move assignment (which might move-assign the base class multiple
- // times).
+ // DR1402: A non-trivially-move-assignable virtual base class no longer
+ // inhibits the declaration of a move assignment (even though it might
+ // move-assign the base class multiple times).
struct NoMove9 : NonTrivialMoveAssign {};
- struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'const DR1402::NoMove10 &'}}
- struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'const DR1402::NoMove11 &'}}
+ struct NoMove10 : virtual NonTrivialMoveAssign {};
+ struct NoMove11 : NonTrivialMoveAssignVBase {};
- struct Test {
- friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{does not match}}
- friend NoMove2::NoMove2(NoMove2 &&); // expected-error {{does not match}}
- friend NoMove3::NoMove3(NoMove3 &&); // expected-error {{does not match}}
- friend NoMove4::NoMove4(NoMove4 &&); // expected-error {{does not match}}
- friend NoMove5::NoMove5(NoMove5 &&); // expected-error {{does not match}}
- friend NoMove6::NoMove6(NoMove6 &&); // expected-error {{does not match}}
- friend NoMove7::NoMove7(NoMove7 &&); // expected-error {{does not match}}
- friend NoMove8::NoMove8(NoMove8 &&); // expected-error {{does not match}}
- friend NoMove9::NoMove9(NoMove9 &&);
- friend NoMove10::NoMove10(NoMove10 &&);
- friend NoMove11::NoMove11(NoMove11 &&);
+ template<typename T> void test(T t) {
+ (void)T(static_cast<T&&>(t)); // ok
+ t = static_cast<T&&>(t); // ok
+ }
+ template void test(NoMove1);
+ template void test(NoMove2);
+ template void test(NoMove3);
+ template void test(NoMove4);
+ template void test(NoMove5);
+ template void test(NoMove6);
+ template void test(NoMove7);
+ template void test(NoMove8);
+ template void test(NoMove9);
+ template void test(NoMove10);
+ template void test(NoMove11);
- friend NoMove1 &NoMove1::operator=(NoMove1 &&); // expected-error {{does not match}}
- friend NoMove2 &NoMove2::operator=(NoMove2 &&); // expected-error {{does not match}}
- friend NoMove3 &NoMove3::operator=(NoMove3 &&); // expected-error {{does not match}}
- friend NoMove4 &NoMove4::operator=(NoMove4 &&); // expected-error {{does not match}}
- friend NoMove5 &NoMove5::operator=(NoMove5 &&); // expected-error {{does not match}}
- friend NoMove6 &NoMove6::operator=(NoMove6 &&); // expected-error {{does not match}}
- friend NoMove7 &NoMove7::operator=(NoMove7 &&); // expected-error {{does not match}}
- friend NoMove8 &NoMove8::operator=(NoMove8 &&); // expected-error {{does not match}}
- friend NoMove9 &NoMove9::operator=(NoMove9 &&);
- friend NoMove10 &NoMove10::operator=(NoMove10 &&); // expected-error {{does not match}}
- friend NoMove11 &NoMove11::operator=(NoMove11 &&); // expected-error {{does not match}}
+ struct CopyOnly {
+ CopyOnly(const CopyOnly&);
+ CopyOnly &operator=(const CopyOnly&);
};
+ struct MoveOnly {
+ MoveOnly(MoveOnly&&); // expected-note {{user-declared move}}
+ MoveOnly &operator=(MoveOnly&&);
+ };
+ template void test(CopyOnly); // ok, copies
+ template void test(MoveOnly); // ok, moves
+ struct CopyAndMove { // expected-note {{implicitly deleted}}
+ CopyOnly co;
+ MoveOnly mo; // expected-note {{deleted copy}}
+ };
+ template void test(CopyAndMove); // ok, copies co, moves mo
+ void test2(CopyAndMove cm) {
+ (void)CopyAndMove(cm); // expected-error {{deleted}}
+ cm = cm; // expected-error {{deleted}}
+ }
}
namespace PR12625 {
Modified: cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp Sun Nov 3 19:48:18 2013
@@ -157,8 +157,8 @@ namespace TrivialityDependsOnImplicitDel
struct NoAccess {
PrivateMove pm;
- // NoAccess's move would be deleted, so is suppressed,
- // so moves of it use PrivateMove's copy ctor, which is trivial.
+ // NoAccess's move is deleted, so moves of it use PrivateMove's copy ctor,
+ // which is trivial.
};
static_assert(__is_trivially_constructible(NoAccess, const NoAccess &), "");
static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), "");
Modified: cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp?rev=193969&r1=193968&r2=193969&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp Sun Nov 3 19:48:18 2013
@@ -9,7 +9,15 @@ template<typename T> struct CopyAssign {
template<typename T> struct MoveAssign {
static T t;
void test() {
- t = static_cast<T&&>(t); // expected-error +{{deleted}}
+ // Overload resolution will ignore a defaulted, deleted move assignment,
+ // so check for it in a different way.
+ T &(T::*f)(T&&) = &T::operator=; // expected-error +{{deleted}}
+ }
+};
+template<typename T> struct MoveOrCopyAssign {
+ static T t;
+ void test() {
+ t = static_cast<T&&>(t); // expected-error +{{copy assignment operator is implicitly deleted}}
}
};
@@ -89,29 +97,32 @@ struct D1 {
AmbiguousCopyAssign a; // expected-note {{field 'a' has multiple copy}}
};
struct D2 {
- D2 &operator=(D2 &&) = default; // expected-note {{here}}
+ D2 &operator=(D2 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
AmbiguousMoveAssign a; // expected-note {{field 'a' has multiple move}}
};
struct D3 {
DeletedCopyAssign a; // expected-note {{field 'a' has a deleted copy}}
};
struct D4 {
- D4 &operator=(D4 &&) = default; // expected-note {{here}}
+ D4 &operator=(D4 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
DeletedMoveAssign a; // expected-note {{field 'a' has a deleted move}}
};
struct D5 {
InaccessibleCopyAssign a; // expected-note {{field 'a' has an inaccessible copy}}
};
struct D6 {
- D6 &operator=(D6 &&) = default; // expected-note {{here}}
+ D6 &operator=(D6 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}}
InaccessibleMoveAssign a; // expected-note {{field 'a' has an inaccessible move}}
};
template struct CopyAssign<D1>; // expected-note {{here}}
template struct MoveAssign<D2>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D2>; // expected-note {{here}}
template struct CopyAssign<D3>; // expected-note {{here}}
template struct MoveAssign<D4>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D4>; // expected-note {{here}}
template struct CopyAssign<D5>; // expected-note {{here}}
template struct MoveAssign<D6>; // expected-note {{here}}
+template struct MoveOrCopyAssign<D6>; // expected-note {{here}}
// -- a direct or virtual base that cannot be copied/moved
struct E1 : AmbiguousCopyAssign {}; // expected-note {{base class 'AmbiguousCopyAssign' has multiple copy}}
More information about the cfe-commits
mailing list