summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-11-04 01:48:18 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-11-04 01:48:18 +0000
commit8b86f2d4010e1c5415ff561945d621858ca81c88 (patch)
treee52e0ef0c7432c3eab40f2d6a176a16e6082a9d7 /clang/lib/Sema
parent7fc270a1718ca1b654a51d83f1bdaebe747954dd (diff)
downloadbcm5719-llvm-8b86f2d4010e1c5415ff561945d621858ca81c88.tar.gz
bcm5719-llvm-8b86f2d4010e1c5415ff561945d621858ca81c88.zip
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). llvm-svn: 193969
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp169
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp4
-rw-r--r--clang/lib/Sema/SemaOverload.cpp17
3 files changed, 33 insertions, 157 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c8338353ea9..006f6aa67bf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9231,11 +9231,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
? 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::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
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::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
? 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(SourceLocation CurrentLocation,
// 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::DeclareImplicitCopyConstructor(
? 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::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
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::DeclareImplicitMoveConstructor(
? 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.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 323cd265e6c..6f72d6598eb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3602,8 +3602,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
// 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
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c6bcf449b77..c0bd2229472 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5448,10 +5448,18 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
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 *Method, DeclAccessPair FoundDecl,
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);
OpenPOWER on IntegriCloud