diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 91 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 11 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 98 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 130 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 6 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p12-0x.cpp | 102 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p25-0x.cpp | 65 | ||||
-rw-r--r-- | test/PCH/cxx0x-default-delete.cpp | 12 | ||||
-rw-r--r-- | test/SemaCXX/type-traits.cpp | 3 |
10 files changed, 442 insertions, 82 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index bf6d62333b..3edb5839ce 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -358,6 +358,22 @@ class CXXRecordDecl : public RecordDecl { /// is illegal in C++98 even if the class has a trivial default constructor. bool HasUninitializedReferenceMember : 1; + /// \brief These flags are \c true if a defaulted corresponding special + /// member can't be fully analyzed without performing overload resolution. + /// @{ + bool NeedOverloadResolutionForMoveConstructor : 1; + bool NeedOverloadResolutionForMoveAssignment : 1; + bool NeedOverloadResolutionForDestructor : 1; + /// @} + + /// \brief These flags are \c true if an implicit defaulted corresponding + /// special member would be defined as deleted. + /// @{ + bool DefaultedMoveConstructorIsDeleted : 1; + bool DefaultedMoveAssignmentIsDeleted : 1; + bool DefaultedDestructorIsDeleted : 1; + /// @} + /// \brief The trivial special members which this class has, per /// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25, /// C++11 [class.dtor]p5, or would have if the member were not suppressed. @@ -566,6 +582,10 @@ class CXXRecordDecl : public RecordDecl { friend class DeclContext; friend class LambdaExpr; + /// \brief Called from setBases and addedMember to notify the class that a + /// direct or virtual base class or a member of class type has been added. + void addedClassSubobject(CXXRecordDecl *Base); + /// \brief Notify the class that member has been added. /// /// This routine helps maintain information about the class based on which @@ -733,6 +753,23 @@ public: return data().FirstFriend != 0; } + /// \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(); + } + /// \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(); + } + /// \brief \c true if we know for sure that this class has an accessible + /// destructor that is not deleted. + bool hasSimpleDestructor() const { + return !hasUserDeclaredDestructor() && + !data().DefaultedDestructorIsDeleted; + } + /// \brief Determine whether this class has any default constructors. bool hasDefaultConstructor() const { return (data().DeclaredSpecialMembers & SMF_DefaultConstructor) || @@ -774,6 +811,12 @@ public: return !(data().DeclaredSpecialMembers & SMF_CopyConstructor); } + /// \brief Determine whether we need to eagerly declare a defaulted copy + /// constructor for this class. + bool needsOverloadResolutionForCopyConstructor() const { + return data().HasMutableFields; + } + /// \brief Determine whether an implicit copy constructor for this type /// would have a parameter with a const-qualified reference type. bool implicitCopyConstructorHasConstParam() const { @@ -803,8 +846,6 @@ public: } /// \brief Determine whether this class has a move constructor. - /// FIXME: This can be wrong if the implicit move constructor would be - /// deleted. bool hasMoveConstructor() const { return (data().DeclaredSpecialMembers & SMF_MoveConstructor) || needsImplicitMoveConstructor(); @@ -824,17 +865,20 @@ public: /// \brief Determine whether this class should get an implicit move /// constructor or if any existing special member function inhibits this. - /// - /// Covers all bullets of C++0x [class.copy]p9 except the last, that the - /// constructor wouldn't be deleted, which is only looked up from a cached - /// result. bool needsImplicitMoveConstructor() const { return !hasFailedImplicitMoveConstructor() && !(data().DeclaredSpecialMembers & SMF_MoveConstructor) && !hasUserDeclaredCopyConstructor() && !hasUserDeclaredCopyAssignment() && !hasUserDeclaredMoveAssignment() && - !hasUserDeclaredDestructor(); + !hasUserDeclaredDestructor() && + !data().DefaultedMoveConstructorIsDeleted; + } + + /// \brief Determine whether we need to eagerly declare a defaulted move + /// constructor for this class. + bool needsOverloadResolutionForMoveConstructor() const { + return data().NeedOverloadResolutionForMoveConstructor; } /// hasUserDeclaredCopyAssignment - Whether this class has a @@ -850,6 +894,12 @@ public: return !(data().DeclaredSpecialMembers & SMF_CopyAssignment); } + /// \brief Determine whether we need to eagerly declare a defaulted copy + /// assignment operator for this class. + bool needsOverloadResolutionForCopyAssignment() const { + return data().HasMutableFields; + } + /// \brief Determine whether an implicit copy assignment operator for this /// type would have a parameter with a const-qualified reference type. bool implicitCopyAssignmentHasConstParam() const { @@ -872,7 +922,6 @@ public: } /// \brief Determine whether this class has a move assignment operator. - /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasMoveAssignment() const { return (data().DeclaredSpecialMembers & SMF_MoveAssignment) || needsImplicitMoveAssignment(); @@ -893,16 +942,20 @@ public: /// \brief Determine whether this class should get an implicit move /// assignment operator or if any existing special member function inhibits /// this. - /// - /// Covers all bullets of C++0x [class.copy]p20 except the last, that the - /// constructor wouldn't be deleted. bool needsImplicitMoveAssignment() const { return !hasFailedImplicitMoveAssignment() && !(data().DeclaredSpecialMembers & SMF_MoveAssignment) && !hasUserDeclaredCopyConstructor() && !hasUserDeclaredCopyAssignment() && !hasUserDeclaredMoveConstructor() && - !hasUserDeclaredDestructor(); + !hasUserDeclaredDestructor() && + !data().DefaultedMoveAssignmentIsDeleted; + } + + /// \brief Determine whether we need to eagerly declare a move assignment + /// operator for this class. + bool needsOverloadResolutionForMoveAssignment() const { + return data().NeedOverloadResolutionForMoveAssignment; } /// hasUserDeclaredDestructor - Whether this class has a @@ -918,9 +971,15 @@ public: return !(data().DeclaredSpecialMembers & SMF_Destructor); } + /// \brief Determine whether we need to eagerly declare a destructor for this + /// class. + bool needsOverloadResolutionForDestructor() const { + return data().NeedOverloadResolutionForDestructor; + } + /// \brief Determine whether this class describes a lambda function object. bool isLambda() const { return hasDefinition() && data().IsLambda; } - + /// \brief For a closure type, retrieve the mapping from captured /// variables and this to the non-static data members that store the /// values or references of the captures. @@ -1067,8 +1126,6 @@ public: /// \brief Determine whether this class has a trivial move constructor /// (C++11 [class.copy]p12) - /// FIXME: This can be wrong if the implicit move constructor would be - /// deleted. bool hasTrivialMoveConstructor() const { return hasMoveConstructor() && (data().HasTrivialSpecialMembers & SMF_MoveConstructor); @@ -1076,8 +1133,6 @@ public: /// \brief Determine whether this class has a non-trivial move constructor /// (C++11 [class.copy]p12) - /// FIXME: This can be wrong if the implicit move constructor would be - /// deleted. bool hasNonTrivialMoveConstructor() const { return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) || (needsImplicitMoveConstructor() && @@ -1099,7 +1154,6 @@ public: /// \brief Determine whether this class has a trivial move assignment operator /// (C++11 [class.copy]p25) - /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasTrivialMoveAssignment() const { return hasMoveAssignment() && (data().HasTrivialSpecialMembers & SMF_MoveAssignment); @@ -1107,7 +1161,6 @@ public: /// \brief Determine whether this class has a non-trivial move assignment /// operator (C++11 [class.copy]p25) - /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasNonTrivialMoveAssignment() const { return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) || (needsImplicitMoveAssignment() && diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 35bc993f73..f288953df6 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1923,6 +1923,17 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.HasInClassInitializer = FromData.HasInClassInitializer; ToData.HasUninitializedReferenceMember = FromData.HasUninitializedReferenceMember; + ToData.NeedOverloadResolutionForMoveConstructor + = FromData.NeedOverloadResolutionForMoveConstructor; + ToData.NeedOverloadResolutionForMoveAssignment + = FromData.NeedOverloadResolutionForMoveAssignment; + ToData.NeedOverloadResolutionForDestructor + = FromData.NeedOverloadResolutionForDestructor; + ToData.DefaultedMoveConstructorIsDeleted + = FromData.DefaultedMoveConstructorIsDeleted; + ToData.DefaultedMoveAssignmentIsDeleted + = FromData.DefaultedMoveAssignmentIsDeleted; + ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted; ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers; ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasConstexprNonCopyMoveConstructor diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 712480655e..73d6ddd6a6 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -42,6 +42,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasOnlyCMembers(true), HasInClassInitializer(false), HasUninitializedReferenceMember(false), + NeedOverloadResolutionForMoveConstructor(false), + NeedOverloadResolutionForMoveAssignment(false), + NeedOverloadResolutionForDestructor(false), + DefaultedMoveConstructorIsDeleted(false), + DefaultedMoveAssignmentIsDeleted(false), + DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), @@ -235,11 +241,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // [...] // -- the constructor selected to copy/move each direct base class // subobject is trivial, and - // FIXME: C++0x: We need to only consider the selected constructor - // instead of all of them. For now, we treat a move constructor as being - // non-trivial if it calls anything other than a trivial move constructor. if (!BaseClassDecl->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + // If the base class doesn't have a simple move constructor, we'll eagerly + // declare it and perform overload resolution to determine which function + // it actually calls. If it does have a simple move constructor, this + // check is correct. if (!BaseClassDecl->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; @@ -248,10 +255,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // [...] // -- the assignment operator selected to copy/move each direct base // class subobject is trivial, and - // FIXME: C++0x: We need to only consider the selected operator instead - // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; + // If the base class doesn't have a simple move assignment, we'll eagerly + // declare it and perform overload resolution to determine which function + // it actually calls. If it does have a simple move assignment, this + // check is correct. if (!BaseClassDecl->hasTrivialMoveAssignment()) data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; @@ -299,6 +308,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (BaseClassDecl->hasUninitializedReferenceMember()) data().HasUninitializedReferenceMember = true; + + addedClassSubobject(BaseClassDecl); } if (VBases.empty()) @@ -307,8 +318,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Create base specifier for any direct or indirect virtual bases. data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); - for (int I = 0, E = VBases.size(); I != E; ++I) + for (int I = 0, E = VBases.size(); I != E; ++I) { + QualType Type = VBases[I]->getType(); + if (!Type->isDependentType()) + addedClassSubobject(Type->getAsCXXRecordDecl()); data().getVBases()[I] = *VBases[I]; + } +} + +void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { + // C++11 [class.copy]p11: + // A defaulted copy/move constructor for a class X is defined as + // deleted if X has: + // -- a direct or virtual base class B that cannot be copied/moved [...] + // -- a non-static data member of class type M (or array thereof) + // that cannot be copied or moved [...] + if (!Subobj->hasSimpleMoveConstructor()) + data().NeedOverloadResolutionForMoveConstructor = true; + + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined as + // deleted if X has: + // -- a direct or virtual base class B that cannot be copied/moved [...] + // -- a non-static data member of class type M (or array thereof) + // that cannot be copied or moved [...] + if (!Subobj->hasSimpleMoveAssignment()) + data().NeedOverloadResolutionForMoveAssignment = true; + + // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5: + // A defaulted [ctor or dtor] for a class X is defined as + // deleted if X has: + // -- any direct or virtual base class [...] has a type with a destructor + // that is deleted or inaccessible from the defaulted [ctor or dtor]. + // -- any non-static data member has a type with a destructor + // that is deleted or inaccessible from the defaulted [ctor or dtor]. + if (!Subobj->hasSimpleDestructor()) { + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForDestructor = true; + } } /// Callback function for CXXRecordDecl::forallBases that acknowledges @@ -636,9 +683,32 @@ void CXXRecordDecl::addedMember(Decl *D) { data().PlainOldData = false; } + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined + // as deleted if X has: + // -- a non-static data member of reference type + if (T->isReferenceType()) + data().DefaultedMoveAssignmentIsDeleted = true; + if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { + addedClassSubobject(FieldRec); + + // C++11 [class.ctor]p5, C++11 [class.copy]p11: + // A defaulted [special member] for a class X is defined as + // deleted if: + // -- X is a union-like class that has a variant member with a + // non-trivial [corresponding special member] + if (isUnion()) { + if (FieldRec->hasNonTrivialMoveConstructor()) + data().DefaultedMoveConstructorIsDeleted = true; + if (FieldRec->hasNonTrivialMoveAssignment()) + data().DefaultedMoveAssignmentIsDeleted = true; + if (FieldRec->hasNonTrivialDestructor()) + data().DefaultedDestructorIsDeleted = true; + } + // C++0x [class.ctor]p5: // A default constructor is trivial [...] if: // -- for all the non-static data members of its class that are of @@ -653,9 +723,11 @@ void CXXRecordDecl::addedMember(Decl *D) { // -- for each non-static data member of X that is of class type (or // an array thereof), the constructor selected to copy/move that // member is trivial; - // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + // If the field doesn't have a simple move constructor, we'll eagerly + // declare the move constructor for this class and we'll decide whether + // it's trivial then. if (!FieldRec->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; @@ -665,9 +737,11 @@ void CXXRecordDecl::addedMember(Decl *D) { // -- for each non-static data member of X that is of class type (or // an array thereof), the assignment operator selected to // copy/move that member is trivial; - // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; + // If the field doesn't have a simple move assignment, we'll eagerly + // declare the move assignment for this class and we'll decide whether + // it's trivial then. if (!FieldRec->hasTrivialMoveAssignment()) data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; @@ -755,6 +829,14 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!T->isLiteralType() || (!Field->hasInClassInitializer() && !isUnion())) data().DefaultedDefaultConstructorIsConstexpr = false; + + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined + // as deleted if X has: + // -- a non-static data member of const non-class type (or array + // thereof) + if (T.isConstQualified()) + data().DefaultedMoveAssignmentIsDeleted = true; } // C++0x [class]p7: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8666453c31..5cca43b548 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5036,12 +5036,6 @@ void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { /// C++11 [class.copy]p25, and C++11 [class.dtor]p5. bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, bool Diagnose) { - // Note that we can't work out CSM for ourselves. Consider this: - // - // struct S { S(int); S(const S&=0) = delete; }; - // - // The same function is a trivial copy constructor but a non-trivial default - // constructor. assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough"); CXXRecordDecl *RD = MD->getParent(); @@ -5337,20 +5331,32 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { if (!ClassDecl->hasUserDeclaredConstructor()) ++ASTContext::NumImplicitDefaultConstructors; - if (!ClassDecl->hasUserDeclaredCopyConstructor()) + if (!ClassDecl->hasUserDeclaredCopyConstructor()) { ++ASTContext::NumImplicitCopyConstructors; - if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor()) + // If the properties or semantics of the copy constructor couldn't be + // determined while the class was being declared, force a declaration + // of it now. + if (ClassDecl->needsOverloadResolutionForCopyConstructor()) + DeclareImplicitCopyConstructor(ClassDecl); + } + + if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor()) { ++ASTContext::NumImplicitMoveConstructors; + if (ClassDecl->needsOverloadResolutionForMoveConstructor()) + DeclareImplicitMoveConstructor(ClassDecl); + } + if (!ClassDecl->hasUserDeclaredCopyAssignment()) { ++ASTContext::NumImplicitCopyAssignmentOperators; - - // If we have a dynamic class, then the copy assignment operator may be + + // If we have a dynamic class, then the copy assignment operator may be // virtual, so we have to declare it immediately. This ensures that, e.g., - // it shows up in the right place in the vtable and that we diagnose - // problems with the implicit exception specification. - if (ClassDecl->isDynamicClass()) + // it shows up in the right place in the vtable and that we diagnose + // problems with the implicit exception specification. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForCopyAssignment()) DeclareImplicitCopyAssignment(ClassDecl); } @@ -5358,18 +5364,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ++ASTContext::NumImplicitMoveAssignmentOperators; // Likewise for the move assignment operator. - if (ClassDecl->isDynamicClass()) + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForMoveAssignment()) DeclareImplicitMoveAssignment(ClassDecl); } if (!ClassDecl->hasUserDeclaredDestructor()) { ++ASTContext::NumImplicitDestructors; - - // If we have a dynamic class, then the destructor may be virtual, so we + + // If we have a dynamic class, then the destructor may be virtual, so we // have to declare the destructor immediately. This ensures that, e.g., it // shows up in the right place in the vtable and that we diagnose problems // with the implicit exception specification. - if (ClassDecl->isDynamicClass()) + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForDestructor()) DeclareImplicitDestructor(ClassDecl); } } @@ -7434,7 +7442,6 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); - DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); // Build an exception specification pointing back at this constructor. FunctionProtoType::ExtProtoInfo EPI; @@ -7442,16 +7449,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( EPI.ExceptionSpecDecl = DefaultCon; DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // We don't need to use SpecialMemberIsTrivial here; triviality for default + // constructors is easy to compute. + DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); + + if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) + DefaultCon->setDeletedAsWritten(); + // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; - + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); - if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) - DefaultCon->setDeletedAsWritten(); - return DefaultCon; } @@ -7785,7 +7796,6 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setDefaulted(); Destructor->setImplicit(); - Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); // Build an exception specification pointing back at this destructor. FunctionProtoType::ExtProtoInfo EPI; @@ -7793,6 +7803,15 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { EPI.ExceptionSpecDecl = Destructor; Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + AddOverriddenMethods(ClassDecl, Destructor); + + // We don't need to use SpecialMemberIsTrivial here; triviality for + // destructors is easy to compute. + Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); + + if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) + Destructor->setDeletedAsWritten(); + // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; @@ -7801,11 +7820,6 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); - AddOverriddenMethods(ClassDecl, Destructor); - - if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) - Destructor->setDeletedAsWritten(); - return Destructor; } @@ -8278,7 +8292,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); - CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI; @@ -8293,14 +8306,14 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { SC_None, SC_None, 0); CopyAssignment->setParams(FromParam); - - // Note that we have added this copy-assignment operator. - ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; - if (Scope *S = getScopeForContext(ClassDecl)) - PushOnScopeChains(CopyAssignment, S, false); - ClassDecl->addDecl(CopyAssignment); - + AddOverriddenMethods(ClassDecl, CopyAssignment); + + CopyAssignment->setTrivial( + ClassDecl->needsOverloadResolutionForCopyAssignment() + ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment) + : ClassDecl->hasTrivialCopyAssignment()); + // C++0x [class.copy]p19: // .... If the class definition does not explicitly declare a copy // assignment operator, there is no user-declared move constructor, and @@ -8309,7 +8322,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) CopyAssignment->setDeletedAsWritten(); - AddOverriddenMethods(ClassDecl, CopyAssignment); + // Note that we have added this copy-assignment operator. + ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(CopyAssignment, S, false); + ClassDecl->addDecl(CopyAssignment); + return CopyAssignment; } @@ -8723,7 +8742,6 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setAccess(AS_public); MoveAssignment->setDefaulted(); MoveAssignment->setImplicit(); - MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI; @@ -8739,8 +8757,12 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { SC_None, 0); MoveAssignment->setParams(FromParam); - // Note that we have added this copy-assignment operator. - ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + AddOverriddenMethods(ClassDecl, MoveAssignment); + + MoveAssignment->setTrivial( + ClassDecl->needsOverloadResolutionForMoveAssignment() + ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment) + : ClassDecl->hasTrivialMoveAssignment()); // C++0x [class.copy]p9: // If the definition of a class X does not explicitly declare a move @@ -8756,11 +8778,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { return 0; } + // Note that we have added this copy-assignment operator. + ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(MoveAssignment, S, false); ClassDecl->addDecl(MoveAssignment); - AddOverriddenMethods(ClassDecl, MoveAssignment); return MoveAssignment; } @@ -9071,7 +9095,6 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Constexpr); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); - CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI; @@ -9080,9 +9103,6 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setType( Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); - // Note that we have declared this constructor. - ++ASTContext::NumImplicitCopyConstructorsDeclared; - // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassLoc, ClassLoc, @@ -9092,9 +9112,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( SC_None, 0); CopyConstructor->setParams(FromParam); - if (Scope *S = getScopeForContext(ClassDecl)) - PushOnScopeChains(CopyConstructor, S, false); - ClassDecl->addDecl(CopyConstructor); + CopyConstructor->setTrivial( + ClassDecl->needsOverloadResolutionForCopyConstructor() + ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) + : ClassDecl->hasTrivialCopyConstructor()); // C++11 [class.copy]p8: // ... If the class definition does not explicitly declare a copy @@ -9104,6 +9125,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) CopyConstructor->setDeletedAsWritten(); + // Note that we have declared this constructor. + ++ASTContext::NumImplicitCopyConstructorsDeclared; + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(CopyConstructor, S, false); + ClassDecl->addDecl(CopyConstructor); + return CopyConstructor; } @@ -9254,7 +9282,6 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( Constexpr); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); - MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI; @@ -9272,6 +9299,11 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( SC_None, 0); MoveConstructor->setParams(FromParam); + MoveConstructor->setTrivial( + ClassDecl->needsOverloadResolutionForMoveConstructor() + ? 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: diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 8c1058e396..94f13948b5 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1100,6 +1100,12 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasOnlyCMembers = Record[Idx++]; Data.HasInClassInitializer = Record[Idx++]; Data.HasUninitializedReferenceMember = Record[Idx++]; + Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++]; + Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++]; + Data.NeedOverloadResolutionForDestructor = Record[Idx++]; + Data.DefaultedMoveConstructorIsDeleted = Record[Idx++]; + Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++]; + Data.DefaultedDestructorIsDeleted = Record[Idx++]; Data.HasTrivialSpecialMembers = Record[Idx++]; Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasConstexprNonCopyMoveConstructor = Record[Idx++]; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f89ae2ef12..ff98d9beb0 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4589,6 +4589,12 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasInClassInitializer); Record.push_back(Data.HasUninitializedReferenceMember); + Record.push_back(Data.NeedOverloadResolutionForMoveConstructor); + Record.push_back(Data.NeedOverloadResolutionForMoveAssignment); + Record.push_back(Data.NeedOverloadResolutionForDestructor); + Record.push_back(Data.DefaultedMoveConstructorIsDeleted); + Record.push_back(Data.DefaultedMoveAssignmentIsDeleted); + Record.push_back(Data.DefaultedDestructorIsDeleted); Record.push_back(Data.HasTrivialSpecialMembers); Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); diff --git a/test/CXX/special/class.copy/p12-0x.cpp b/test/CXX/special/class.copy/p12-0x.cpp index c15e8b873c..17b3191d1d 100644 --- a/test/CXX/special/class.copy/p12-0x.cpp +++ b/test/CXX/special/class.copy/p12-0x.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s +// expected-no-diagnostics + template<typename T, bool B> struct trivially_copyable_check { static_assert(B == __has_trivial_copy(T), ""); static_assert(B == __is_trivially_constructible(T, T), ""); @@ -52,9 +54,7 @@ using _ = trivially_copyable<TemplateCtorMember>; struct MutableTemplateCtorMember { mutable TemplateCtor mtc; }; -// FIXME: This is wrong! The "trivial" copy constructor calls the templated -// constructor for the mutable member. -static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}} +static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), ""); struct MutableTemplateCtorMember2 { MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default; @@ -118,3 +118,99 @@ static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), ""); static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), ""); static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), ""); static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), ""); + +struct TemplateCtorNoMove { + TemplateCtorNoMove(const TemplateCtorNoMove &) = default; + template<typename T> TemplateCtorNoMove(T &&); +}; +static_assert(__is_trivially_constructible(TemplateCtorNoMove, const TemplateCtorNoMove &), ""); +static_assert(!__is_trivially_constructible(TemplateCtorNoMove, TemplateCtorNoMove &&), ""); + +struct UseTemplateCtorNoMove { + TemplateCtorNoMove tcnm; +}; +static_assert(__is_trivially_constructible(UseTemplateCtorNoMove, const UseTemplateCtorNoMove &), ""); +static_assert(!__is_trivially_constructible(UseTemplateCtorNoMove, UseTemplateCtorNoMove &&), ""); + +struct TemplateCtorNoMoveSFINAE { + TemplateCtorNoMoveSFINAE(const TemplateCtorNoMoveSFINAE &) = default; + template<typename T, typename U = typename T::error> TemplateCtorNoMoveSFINAE(T &&); +}; +static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, const TemplateCtorNoMoveSFINAE &), ""); +static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, TemplateCtorNoMoveSFINAE &&), ""); + +struct UseTemplateCtorNoMoveSFINAE { + TemplateCtorNoMoveSFINAE tcnm; +}; +static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, const UseTemplateCtorNoMoveSFINAE &), ""); +static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, UseTemplateCtorNoMoveSFINAE &&), ""); + +namespace TrivialityDependsOnImplicitDeletion { + struct PrivateMove { + PrivateMove(const PrivateMove &) = default; + private: + PrivateMove(PrivateMove &&); + friend class Access; + }; + static_assert(__is_trivially_constructible(PrivateMove, const PrivateMove &), ""); + static_assert(!__is_trivially_constructible(PrivateMove, PrivateMove &&), ""); + + struct NoAccess { + Privat |