From 328aae595c29f0f06892acba1b1065e8ba363801 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 30 Nov 2012 05:11:39 +0000 Subject: [PATCH] Refactor to reduce duplication in handling of special member functions. No functionality change. llvm-svn: 168977 --- clang/include/clang/AST/DeclCXX.h | 218 ++++++++------------------- clang/lib/AST/ASTImporter.cpp | 22 +-- clang/lib/AST/DeclCXX.cpp | 238 ++++++++++-------------------- clang/lib/Serialization/ASTReaderDecl.cpp | 22 +-- clang/lib/Serialization/ASTWriter.cpp | 22 +-- 5 files changed, 155 insertions(+), 367 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c949dbb..1678cd9 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -272,32 +272,25 @@ class CXXRecordDecl : public RecordDecl { friend void TagDecl::startDefinition(); + /// Values used in DefinitionData fields to represent special members. + enum SpecialMemberFlags { + SMF_DefaultConstructor = 0x1, + SMF_CopyConstructor = 0x2, + SMF_MoveConstructor = 0x4, + SMF_CopyAssignment = 0x8, + SMF_MoveAssignment = 0x10, + SMF_Destructor = 0x20, + SMF_All = 0x3f + }; + struct DefinitionData { DefinitionData(CXXRecordDecl *D); - /// UserDeclaredConstructor - True when this class has a - /// user-declared constructor. + /// \brief True if this class has any user-declared constructors. bool UserDeclaredConstructor : 1; - /// UserDeclaredCopyConstructor - True when this class has a - /// user-declared copy constructor. - bool UserDeclaredCopyConstructor : 1; - - /// UserDeclareMoveConstructor - True when this class has a - /// user-declared move constructor. - bool UserDeclaredMoveConstructor : 1; - - /// UserDeclaredCopyAssignment - True when this class has a - /// user-declared copy assignment operator. - bool UserDeclaredCopyAssignment : 1; - - /// UserDeclareMoveAssignment - True when this class has a - /// user-declared move assignment. - bool UserDeclaredMoveAssignment : 1; - - /// UserDeclaredDestructor - True when this class has a - /// user-declared destructor. - bool UserDeclaredDestructor : 1; + /// The user-declared special members which this class has. + unsigned UserDeclaredSpecialMembers : 6; /// Aggregate - True when this class is an aggregate. bool Aggregate : 1; @@ -360,21 +353,14 @@ class CXXRecordDecl : public RecordDecl { /// \brief True if any field has an in-class initializer. bool HasInClassInitializer : 1; - /// HasTrivialDefaultConstructor - True when, if this class has a default - /// constructor, this default constructor is trivial. - /// - /// C++0x [class.ctor]p5 - /// A default constructor is trivial if it is not user-provided and if - /// -- its class has no virtual functions and no virtual base classes, - /// and - /// -- no non-static data member of its class has a - /// brace-or-equal-initializer, and - /// -- all the direct base classes of its class have trivial - /// default constructors, and - /// -- for all the nonstatic data members of its class that are of class - /// type (or array thereof), each such class has a trivial - /// default constructor. - bool HasTrivialDefaultConstructor : 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. + unsigned HasTrivialSpecialMembers : 6; + + /// HasIrrelevantDestructor - True when this class has a destructor with no + /// semantic effect. + bool HasIrrelevantDestructor : 1; /// HasConstexprNonCopyMoveConstructor - True when this class has at least /// one user-declared constexpr constructor which is neither the copy nor @@ -389,80 +375,6 @@ class CXXRecordDecl : public RecordDecl { /// default constructor (either user-declared or implicitly declared). bool HasConstexprDefaultConstructor : 1; - /// HasTrivialCopyConstructor - True when this class has a trivial copy - /// constructor. - /// - /// C++0x [class.copy]p13: - /// A copy/move constructor for class X is trivial if it is neither - /// user-provided and if - /// -- class X has no virtual functions and no virtual base classes, and - /// -- the constructor selected to copy/move each direct base class - /// subobject is trivial, and - /// -- 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; - /// otherwise the copy/move constructor is non-trivial. - bool HasTrivialCopyConstructor : 1; - - /// HasTrivialMoveConstructor - True when this class has a trivial move - /// constructor. - /// - /// C++0x [class.copy]p13: - /// A copy/move constructor for class X is trivial if it is neither - /// user-provided and if - /// -- class X has no virtual functions and no virtual base classes, and - /// -- the constructor selected to copy/move each direct base class - /// subobject is trivial, and - /// -- 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; - /// otherwise the copy/move constructor is non-trivial. - bool HasTrivialMoveConstructor : 1; - - /// HasTrivialCopyAssignment - True when this class has a trivial copy - /// assignment operator. - /// - /// C++0x [class.copy]p27: - /// A copy/move assignment operator for class X is trivial if it is - /// neither user-provided nor deleted and if - /// -- class X has no virtual functions and no virtual base classes, and - /// -- the assignment operator selected to copy/move each direct base - /// class subobject is trivial, and - /// -- 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; - /// otherwise the copy/move assignment operator is non-trivial. - bool HasTrivialCopyAssignment : 1; - - /// HasTrivialMoveAssignment - True when this class has a trivial move - /// assignment operator. - /// - /// C++0x [class.copy]p27: - /// A copy/move assignment operator for class X is trivial if it is - /// neither user-provided nor deleted and if - /// -- class X has no virtual functions and no virtual base classes, and - /// -- the assignment operator selected to copy/move each direct base - /// class subobject is trivial, and - /// -- 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; - /// otherwise the copy/move assignment operator is non-trivial. - bool HasTrivialMoveAssignment : 1; - - /// HasTrivialDestructor - True when this class has a trivial destructor. - /// - /// C++ [class.dtor]p3. A destructor is trivial if it is an - /// implicitly-declared destructor and if: - /// * all of the direct base classes of its class have trivial destructors - /// and - /// * for all of the non-static data members of its class that are of class - /// type (or array thereof), each such class has a trivial destructor. - bool HasTrivialDestructor : 1; - - /// HasIrrelevantDestructor - True when this class has a destructor with no - /// semantic effect. - bool HasIrrelevantDestructor : 1; - /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least /// one non-static data member or base class of non-literal or volatile /// type. @@ -472,27 +384,13 @@ class CXXRecordDecl : public RecordDecl { /// already computed and are available. bool ComputedVisibleConversions : 1; - /// \brief Whether we have a C++0x user-provided default constructor (not + /// \brief Whether we have a C++11 user-provided default constructor (not /// explicitly deleted or defaulted). bool UserProvidedDefaultConstructor : 1; - /// \brief Whether we have already declared the default constructor. - bool DeclaredDefaultConstructor : 1; - - /// \brief Whether we have already declared the copy constructor. - bool DeclaredCopyConstructor : 1; - - /// \brief Whether we have already declared the move constructor. - bool DeclaredMoveConstructor : 1; - - /// \brief Whether we have already declared the copy-assignment operator. - bool DeclaredCopyAssignment : 1; - - /// \brief Whether we have already declared the move-assignment operator. - bool DeclaredMoveAssignment : 1; - - /// \brief Whether we have already declared a destructor within the class. - bool DeclaredDestructor : 1; + /// \brief The special members which have been declared for this class, + /// either by the user or implicitly. + unsigned DeclaredSpecialMembers : 6; /// \brief Whether an implicit copy constructor would have a const-qualified /// parameter. @@ -824,8 +722,7 @@ public: /// \brief Determine whether this class has any default constructors. bool hasDefaultConstructor() const { - return !data().UserDeclaredConstructor || - data().DeclaredDefaultConstructor; + return !data().UserDeclaredConstructor || hasDeclaredDefaultConstructor(); } /// \brief Determine if we need to declare a default constructor for @@ -833,14 +730,13 @@ public: /// /// This value is used for lazy creation of default constructors. bool needsImplicitDefaultConstructor() const { - return !data().UserDeclaredConstructor && - !data().DeclaredDefaultConstructor; + return !data().UserDeclaredConstructor && !hasDeclaredDefaultConstructor(); } /// \brief Determine whether any default constructors have been declared for /// this class (either explicitly or implicitly). bool hasDeclaredDefaultConstructor() const { - return data().DeclaredDefaultConstructor; + return data().DeclaredSpecialMembers & SMF_DefaultConstructor; } /// hasConstCopyConstructor - Determines whether this class has a @@ -886,7 +782,7 @@ public: /// user-declared copy constructor. When false, a copy constructor /// will be implicitly declared. bool hasUserDeclaredCopyConstructor() const { - return data().UserDeclaredCopyConstructor; + return data().UserDeclaredSpecialMembers & SMF_CopyConstructor; } /// \brief Determine whether this class has had its copy constructor @@ -894,7 +790,7 @@ public: /// /// This value is used for lazy creation of copy constructors. bool hasDeclaredCopyConstructor() const { - return data().DeclaredCopyConstructor; + return data().DeclaredSpecialMembers & SMF_CopyConstructor; } /// \brief Determine whether an implicit copy constructor for this type @@ -915,20 +811,20 @@ public: /// declared move constructor or assignment operator. When false, a /// move constructor and assignment operator may be implicitly declared. bool hasUserDeclaredMoveOperation() const { - return data().UserDeclaredMoveConstructor || - data().UserDeclaredMoveAssignment; + return data().UserDeclaredSpecialMembers & + (SMF_MoveConstructor | SMF_MoveAssignment); } /// \brief Determine whether this class has had a move constructor /// declared by the user. bool hasUserDeclaredMoveConstructor() const { - return data().UserDeclaredMoveConstructor; + return data().UserDeclaredSpecialMembers & SMF_MoveConstructor; } /// \brief Determine whether this class has had a move constructor /// declared. bool hasDeclaredMoveConstructor() const { - return data().DeclaredMoveConstructor; + return data().DeclaredSpecialMembers & SMF_MoveConstructor; } /// \brief Determine whether implicit move constructor generation for this @@ -962,7 +858,7 @@ public: /// user-declared copy assignment operator. When false, a copy /// assigment operator will be implicitly declared. bool hasUserDeclaredCopyAssignment() const { - return data().UserDeclaredCopyAssignment; + return data().UserDeclaredSpecialMembers & SMF_CopyAssignment; } /// \brief Determine whether this class has had its copy assignment operator @@ -970,7 +866,7 @@ public: /// /// This value is used for lazy creation of copy assignment operators. bool hasDeclaredCopyAssignment() const { - return data().DeclaredCopyAssignment; + return data().DeclaredSpecialMembers & SMF_CopyAssignment; } /// \brief Determine whether an implicit copy assignment operator for this @@ -991,13 +887,13 @@ public: /// \brief Determine whether this class has had a move assignment /// declared by the user. bool hasUserDeclaredMoveAssignment() const { - return data().UserDeclaredMoveAssignment; + return data().UserDeclaredSpecialMembers & SMF_MoveAssignment; } /// hasDeclaredMoveAssignment - Whether this class has a /// declared move assignment operator. bool hasDeclaredMoveAssignment() const { - return data().DeclaredMoveAssignment; + return data().DeclaredSpecialMembers & SMF_MoveAssignment; } /// \brief Determine whether implicit move assignment generation for this @@ -1031,14 +927,16 @@ public: /// user-declared destructor. When false, a destructor will be /// implicitly declared. bool hasUserDeclaredDestructor() const { - return data().UserDeclaredDestructor; + return data().UserDeclaredSpecialMembers & SMF_Destructor; } /// \brief Determine whether this class has had its destructor declared, /// either via the user or via an implicit declaration. /// /// This value is used for lazy creation of destructors. - bool hasDeclaredDestructor() const { return data().DeclaredDestructor; } + bool hasDeclaredDestructor() const { + return data().DeclaredSpecialMembers & SMF_Destructor; + } /// \brief Determine whether this class describes a lambda function object. bool isLambda() const { return hasDefinition() && data().IsLambda; } @@ -1127,13 +1025,15 @@ public: /// (C++11 [class.ctor]p5). /// FIXME: This can be wrong when the class has multiple default constructors. bool hasTrivialDefaultConstructor() const { - return hasDefaultConstructor() && data().HasTrivialDefaultConstructor; + return hasDefaultConstructor() && + (data().HasTrivialSpecialMembers & SMF_DefaultConstructor); } /// \brief Determine whether this class has a non-trivial default constructor /// (C++11 [class.ctor]p5). bool hasNonTrivialDefaultConstructor() const { - return hasDefaultConstructor() && !data().HasTrivialDefaultConstructor; + return hasDefaultConstructor() && + !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor); } /// \brief Determine whether this class has at least one constexpr constructor @@ -1162,13 +1062,13 @@ public: /// (C++ [class.copy]p6, C++11 [class.copy]p12) /// FIXME: This can be wrong if the class has multiple copy constructors. bool hasTrivialCopyConstructor() const { - return data().HasTrivialCopyConstructor; + return data().HasTrivialSpecialMembers & SMF_CopyConstructor; } /// \brief Determine whether this class has a non-trivial copy constructor /// (C++ [class.copy]p6, C++11 [class.copy]p12) bool hasNonTrivialCopyConstructor() const { - return !data().HasTrivialCopyConstructor; + return !(data().HasTrivialSpecialMembers & SMF_CopyConstructor); } /// \brief Determine whether this class has a trivial move constructor @@ -1176,7 +1076,7 @@ public: /// FIXME: This can be wrong if the class has multiple move constructors, /// or if the implicit move constructor would be deleted. bool hasTrivialMoveConstructor() const { - return data().HasTrivialMoveConstructor && + return (data().HasTrivialSpecialMembers & SMF_MoveConstructor) && (hasDeclaredMoveConstructor() || needsImplicitMoveConstructor()); } @@ -1185,7 +1085,7 @@ public: /// FIXME: This can be wrong if the implicit move constructor would be /// deleted. bool hasNonTrivialMoveConstructor() const { - return !data().HasTrivialMoveConstructor && + return !(data().HasTrivialSpecialMembers & SMF_MoveConstructor) && (hasDeclaredMoveConstructor() || needsImplicitMoveConstructor()); } @@ -1194,13 +1094,13 @@ public: /// FIXME: This can be wrong if the class has multiple copy assignment /// operators. bool hasTrivialCopyAssignment() const { - return data().HasTrivialCopyAssignment; + return data().HasTrivialSpecialMembers & SMF_CopyAssignment; } /// \brief Determine whether this class has a non-trivial copy assignment /// operator (C++ [class.copy]p11, C++11 [class.copy]p25) bool hasNonTrivialCopyAssignment() const { - return !data().HasTrivialCopyAssignment; + return !(data().HasTrivialSpecialMembers & SMF_CopyAssignment); } /// \brief Determine whether this class has a trivial move assignment operator @@ -1208,7 +1108,7 @@ public: /// FIXME: This can be wrong if the class has multiple move assignment /// operators, or if the implicit move assignment operator would be deleted. bool hasTrivialMoveAssignment() const { - return data().HasTrivialMoveAssignment && + return (data().HasTrivialSpecialMembers & SMF_MoveAssignment) && (hasDeclaredMoveAssignment() || needsImplicitMoveAssignment()); } @@ -1216,17 +1116,21 @@ public: /// operator (C++11 [class.copy]p25) /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasNonTrivialMoveAssignment() const { - return !data().HasTrivialMoveAssignment && + return !(data().HasTrivialSpecialMembers & SMF_MoveAssignment) && (hasDeclaredMoveAssignment() || needsImplicitMoveAssignment()); } /// \brief Determine whether this class has a trivial destructor /// (C++ [class.dtor]p3) - bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } + bool hasTrivialDestructor() const { + return data().HasTrivialSpecialMembers & SMF_Destructor; + } /// \brief Determine whether this class has a non-trivial destructor /// (C++ [class.dtor]p3) - bool hasNonTrivialDestructor() const { return !data().HasTrivialDestructor; } + bool hasNonTrivialDestructor() const { + return !(data().HasTrivialSpecialMembers & SMF_Destructor); + } // hasIrrelevantDestructor - Whether this class has a destructor which has no // semantic effect. Any such destructor will be trivial, public, defaulted diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 054cd96..200bf21 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1908,11 +1908,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data(); struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data(); ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor; - ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor; - ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor; - ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment; - ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment; - ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor; + ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers; ToData.Aggregate = FromData.Aggregate; ToData.PlainOldData = FromData.PlainOldData; ToData.Empty = FromData.Empty; @@ -1926,30 +1922,20 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.HasMutableFields = FromData.HasMutableFields; ToData.HasOnlyCMembers = FromData.HasOnlyCMembers; ToData.HasInClassInitializer = FromData.HasInClassInitializer; - ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor; + ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers; + ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasConstexprNonCopyMoveConstructor = FromData.HasConstexprNonCopyMoveConstructor; ToData.DefaultedDefaultConstructorIsConstexpr = FromData.DefaultedDefaultConstructorIsConstexpr; ToData.HasConstexprDefaultConstructor = FromData.HasConstexprDefaultConstructor; - ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor; - ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor; - ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment; - ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment; - ToData.HasTrivialDestructor = FromData.HasTrivialDestructor; - ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasNonLiteralTypeFieldsOrBases = FromData.HasNonLiteralTypeFieldsOrBases; // ComputedVisibleConversions not imported. ToData.UserProvidedDefaultConstructor = FromData.UserProvidedDefaultConstructor; - ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor; - ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor; - ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor; - ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment; - ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment; - ToData.DeclaredDestructor = FromData.DeclaredDestructor; + ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers; ToData.ImplicitCopyConstructorHasConstParam = FromData.ImplicitCopyConstructorHasConstParam; ToData.ImplicitCopyAssignmentHasConstParam diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index a3c0bab..ba87764 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -36,26 +36,19 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { } CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) - : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), - UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false), - UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false), + : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasOnlyCMembers(true), HasInClassInitializer(false), - HasTrivialDefaultConstructor(true), + HasTrivialSpecialMembers(SMF_All), + HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), DefaultedDefaultConstructorIsConstexpr(true), - HasConstexprDefaultConstructor(false), HasTrivialCopyConstructor(true), - HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), - HasTrivialMoveAssignment(true), HasTrivialDestructor(true), - HasIrrelevantDestructor(true), + HasConstexprDefaultConstructor(false), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), - UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), - DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), - DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), - DeclaredDestructor(false), + UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), ImplicitCopyConstructorHasConstParam(true), ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), @@ -212,25 +205,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // T is a class type, but not a union type, with ... no virtual base // classes data().Empty = false; - - // C++ [class.ctor]p5: - // A default constructor is trivial [...] if: - // -- its class has [...] no virtual bases - data().HasTrivialDefaultConstructor = false; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is neither - // user-provided nor deleted and if - // -- class X has no virtual functions and no virtual base classes, and - data().HasTrivialCopyConstructor = false; - data().HasTrivialMoveConstructor = false; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted and if - // -- class X has no virtual functions and no virtual base classes, and - data().HasTrivialCopyAssignment = false; - data().HasTrivialMoveAssignment = false; + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor, copy/move constructor, or copy/move assignment + // operator for a class X] is trivial [...] if: + // -- class X has [...] no virtual base classes + data().HasTrivialSpecialMembers &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] @@ -247,8 +227,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // -- all the direct base classes of its class have trivial default // constructors. if (!BaseClassDecl->hasTrivialDefaultConstructor()) - data().HasTrivialDefaultConstructor = false; - + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; + // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] // [...] @@ -258,9 +238,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // 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().HasTrivialCopyConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; if (!BaseClassDecl->hasTrivialMoveConstructor()) - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] @@ -270,9 +250,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // FIXME: C++0x: We need to only consider the selected operator instead // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) - data().HasTrivialCopyAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; if (!BaseClassDecl->hasTrivialMoveAssignment()) - data().HasTrivialMoveAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; // C++11 [class.ctor]p6: // If that user-written default constructor would satisfy the @@ -286,7 +266,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // A destructor is trivial if all the direct base classes of its class // have trivial destructors. if (!BaseClassDecl->hasTrivialDestructor()) - data().HasTrivialDestructor = false; + data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!BaseClassDecl->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; @@ -529,24 +509,13 @@ void CXXRecordDecl::addedMember(Decl *D) { // A class that declares or inherits a virtual function is called a // polymorphic class. data().Polymorphic = true; - - // C++0x [class.ctor]p5 - // A default constructor is trivial [...] if: - // -- its class has no virtual functions [...] - data().HasTrivialDefaultConstructor = false; - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if [...] + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor, copy/move constructor, or copy/move + // assignment operator for a class X] is trivial [...] if: // -- class X has no virtual functions [...] - data().HasTrivialCopyConstructor = false; - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= SMF_Destructor; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if [...] - // -- class X has no virtual functions [...] - data().HasTrivialCopyAssignment = false; - data().HasTrivialMoveAssignment = false; - // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no virtual functions @@ -560,6 +529,9 @@ void CXXRecordDecl::addedMember(Decl *D) { if (ASTMutationListener *L = getASTMutationListener()) L->AddedCXXImplicitMember(data().Definition, D); + // The kind of special member this declaration is, if any. + unsigned SMKind = 0; + // Handle constructors. if (CXXConstructorDecl *Constructor = dyn_cast(D)) { if (!Constructor->isImplicit()) { @@ -579,45 +551,23 @@ void CXXRecordDecl::addedMember(Decl *D) { bool UserProvided = Constructor->isUserProvided(); if (Constructor->isDefaultConstructor()) { - data().DeclaredDefaultConstructor = true; - if (UserProvided) { - // C++0x [class.ctor]p5: - // A default constructor is trivial if it is not user-provided [...] - data().HasTrivialDefaultConstructor = false; + SMKind |= SMF_DefaultConstructor; + + if (UserProvided) data().UserProvidedDefaultConstructor = true; - } if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; } - // Note when we have a user-declared copy or move constructor, which will - // suppress the implicit declaration of those constructors. if (!FunTmpl) { unsigned Quals; if (Constructor->isCopyConstructor(Quals)) { - if (!Constructor->isImplicit()) - data().UserDeclaredCopyConstructor = true; - data().DeclaredCopyConstructor = true; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is not - // user-provided [...] - if (UserProvided) - data().HasTrivialCopyConstructor = false; + SMKind |= SMF_CopyConstructor; if (Quals & Qualifiers::Const) data().HasDeclaredCopyConstructorWithConstParam = true; - } else if (Constructor->isMoveConstructor()) { - if (!Constructor->isImplicit()) - data().UserDeclaredMoveConstructor = true; - data().DeclaredMoveConstructor = true; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is not - // user-provided [...] - if (UserProvided) - data().HasTrivialMoveConstructor = false; - } + } else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; } // Record if we see any constexpr constructors which are neither copy @@ -634,57 +584,25 @@ void CXXRecordDecl::addedMember(Decl *D) { if (getASTContext().getLangOpts().CPlusPlus0x ? UserProvided : !Constructor->isImplicit()) data().Aggregate = false; - - return; } // Handle destructors. if (CXXDestructorDecl *DD = dyn_cast(D)) { - data().DeclaredDestructor = true; + SMKind |= SMF_Destructor; - if (!DD->isImplicit()) { - data().UserDeclaredDestructor = true; + if (!DD->isImplicit()) data().HasIrrelevantDestructor = false; - // C++ [class]p4: - // A POD-struct is an aggregate class that has [...] no user-defined - // destructor. - // This bit is the C++03 POD bit, not the 0x one. - data().PlainOldData = false; - } - // C++11 [class.dtor]p5: - // A destructor is trivial if it is not user-provided and if - // -- the destructor is not virtual. - if (DD->isUserProvided() || DD->isVirtual()) - data().HasTrivialDestructor = false; - - return; + // A destructor is trivial if [...] the destructor is not virtual. + if (DD->isVirtual()) + data().HasTrivialSpecialMembers &= ~SMF_Destructor; } // Handle member functions. if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isCopyAssignmentOperator()) { - // Suppress the implicit declaration of a copy constructor. - data().DeclaredCopyAssignment = true; - - if (!Method->isImplicit()) { - data().UserDeclaredCopyAssignment = true; - - // C++ [class]p4: - // A POD-struct is an aggregate class that [...] has no user-defined - // copy assignment operator [...]. - // This is the C++03 bit only. - data().PlainOldData = false; - - // C++11 [class.copy]p25: - // A copy/move assignment operator for class X is trivial if it is - // not user-provided [...] - // FIXME: This is bogus. Having one user-provided copy assignment - // doesn't stop another one from being trivial. - if (Method->isUserProvided()) - data().HasTrivialCopyAssignment = false; - } + SMKind |= SMF_CopyAssignment; const ReferenceType *ParamTy = Method->getParamDecl(0)->getType()->getAs(); @@ -692,34 +610,16 @@ void CXXRecordDecl::addedMember(Decl *D) { data().HasDeclaredCopyAssignmentWithConstParam = true; } - if (Method->isMoveAssignmentOperator()) { - data().DeclaredMoveAssignment = true; - - if (!Method->isImplicit()) { - data().UserDeclaredMoveAssignment = true; - - // This is an extension in C++03 mode, but we'll keep consistency by - // taking a move assignment operator to induce non-POD-ness - data().PlainOldData = false; - - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted [...] - if (Method->isUserProvided()) - data().HasTrivialMoveAssignment = false; - } - } + if (Method->isMoveAssignmentOperator()) + SMKind |= SMF_MoveAssignment; // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast(D)) { - // We don't record specializations. - if (Conversion->getPrimaryTemplate()) - return; - // FIXME: We intentionally don't use the decl's access here because it // hasn't been set yet. That's really just a misdesign in Sema. - - if (FunTmpl) { + if (Conversion->getPrimaryTemplate()) { + // We don't record specializations. + } else if (FunTmpl) { if (FunTmpl->getPreviousDecl()) data().Conversions.replace(FunTmpl->getPreviousDecl(), FunTmpl); @@ -734,9 +634,40 @@ void CXXRecordDecl::addedMember(Decl *D) { } } + if (SMKind) { + // Note when we have declared a declared special member, and suppress the + // implicit declaration of this special member. + data().DeclaredSpecialMembers |= SMKind; + + if (!Method->isImplicit()) { + data().UserDeclaredSpecialMembers |= SMKind; + + // C++03 [class]p4: + // A POD-struct is an aggregate class that has [...] no user-defined + // copy assignment operator and no user-defined destructor. + // + // Since the POD bit is meant to be C++03 POD-ness, and in C++03, + // aggregates could not have any constructors, clear it even for an + // explicitly defaulted or deleted constructor. + // type is technically an aggregate in C++0x since it wouldn't be in 03. + // + // Also, a user-declared move assignment operator makes a class non-POD. + // This is an extension in C++03. + data().PlainOldData = false; + } + + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25, + // C++11 [class.dtor]p5: + // A [special member] is trivial if it is not user-provided [...] + // FIXME: This is bogus. A class can have both (say) a trivial copy + // constructor *and* a user-provided copy constructor. + if (Method->isUserProvided()) + data().HasTrivialSpecialMembers &= ~SMKind; + } + return; } - + // Handle non-static data members. if (FieldDecl *Field = dyn_cast(D)) { // C++ [class.bit]p2: @@ -796,7 +727,7 @@ void CXXRecordDecl::addedMember(Decl *D) { data().PlainOldData = false; if (T->isReferenceType()) { - data().HasTrivialDefaultConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++0x [class]p7: // A standard-layout class is a class that: @@ -814,7 +745,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [class]p5: // A default constructor is trivial if [...] no non-static data member // of its class has a brace-or-equal-initializer. - data().HasTrivialDefaultConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no @@ -835,7 +766,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // class type (or array thereof), each such class has a trivial // default constructor. if (!FieldRec->hasTrivialDefaultConstructor()) - data().HasTrivialDefaultConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] @@ -845,9 +776,9 @@ void CXXRecordDecl::addedMember(Decl *D) { // member is trivial; // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) - data().HasTrivialCopyConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; if (!FieldRec->hasTrivialMoveConstructor()) - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] @@ -857,12 +788,12 @@ void CXXRecordDecl::addedMember(Decl *D) { // copy/move that member is trivial; // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) - data().HasTrivialCopyAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; if (!FieldRec->hasTrivialMoveAssignment()) - data().HasTrivialMoveAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; if (!FieldRec->hasTrivialDestructor()) - data().HasTrivialDestructor = false; + data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!FieldRec->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) @@ -1254,12 +1185,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { // non-trivial. struct DefinitionData &Data = data(); Data.PlainOldData = false; - Data.HasTrivialDefaultConstructor = false; - Data.HasTrivialCopyConstructor = false; - Data.HasTrivialMoveConstructor = false; - Data.HasTrivialCopyAssignment = false; - Data.HasTrivialMoveAssignment = false; - Data.HasTrivialDestructor = false; + Data.HasTrivialSpecialMembers = 0; Data.HasIrrelevantDestructor = false; } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 751b989..d93c28a 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1083,11 +1083,7 @@ void ASTDeclReader::ReadCXXDefinitionData( const RecordData &Record, unsigned &Idx) { // Note: the caller has deserialized the IsLambda bit already. Data.UserDeclaredConstructor = Record[Idx++]; - Data.UserDeclaredCopyConstructor = Record[Idx++]; - Data.UserDeclaredMoveConstructor = Record[Idx++]; - Data.UserDeclaredCopyAssignment = Record[Idx++]; - Data.UserDeclaredMoveAssignment = Record[Idx++]; - Data.UserDeclaredDestructor = Record[Idx++]; + Data.UserDeclaredSpecialMembers = Record[Idx++]; Data.Aggregate = Record[Idx++]; Data.PlainOldData = Record[Idx++]; Data.Empty = Record[Idx++]; @@ -1101,25 +1097,15 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasMutableFields = Record[Idx++]; Data.HasOnlyCMembers = Record[Idx++]; Data.HasInClassInitializer = Record[Idx++]; - Data.HasTrivialDefaultConstructor = Record[Idx++]; + Data.HasTrivialSpecialMembers = Record[Idx++]; + Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasConstexprNonCopyMoveConstructor = Record[Idx++]; Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++]; Data.HasConstexprDefaultConstructor = Record[Idx++]; - Data.HasTrivialCopyConstructor = Record[Idx++]; - Data.HasTrivialMoveConstructor = Record[Idx++]; - Data.HasTrivialCopyAssignment = Record[Idx++]; - Data.HasTrivialMoveAssignment = Record[Idx++]; - Data.HasTrivialDestructor = Record[Idx++]; - Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; Data.UserProvidedDefaultConstructor = Record[Idx++]; - Data.DeclaredDefaultConstructor = Record[Idx++]; - Data.DeclaredCopyConstructor = Record[Idx++]; - Data.DeclaredMoveConstructor = Record[Idx++]; - Data.DeclaredCopyAssignment = Record[Idx++]; - Data.DeclaredMoveAssignment = Record[Idx++]; - Data.DeclaredDestructor = Record[Idx++]; + Data.DeclaredSpecialMembers = Record[Idx++]; Data.ImplicitCopyConstructorHasConstParam = Record[Idx++]; Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++]; Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index d57dba8..85293aa 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4574,11 +4574,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; Record.push_back(Data.IsLambda); Record.push_back(Data.UserDeclaredConstructor); - Record.push_back(Data.UserDeclaredCopyConstructor); - Record.push_back(Data.UserDeclaredMoveConstructor); - Record.push_back(Data.UserDeclaredCopyAssignment); - Record.push_back(Data.UserDeclaredMoveAssignment); - Record.push_back(Data.UserDeclaredDestructor); + Record.push_back(Data.UserDeclaredSpecialMembers); Record.push_back(Data.Aggregate); Record.push_back(Data.PlainOldData); Record.push_back(Data.Empty); @@ -4592,25 +4588,15 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasMutableFields); Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasInClassInitializer); - Record.push_back(Data.HasTrivialDefaultConstructor); + Record.push_back(Data.HasTrivialSpecialMembers); + Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr); Record.push_back(Data.HasConstexprDefaultConstructor); - Record.push_back(Data.HasTrivialCopyConstructor); - Record.push_back(Data.HasTrivialMoveConstructor); - Record.push_back(Data.HasTrivialCopyAssignment); - Record.push_back(Data.HasTrivialMoveAssignment); - Record.push_back(Data.HasTrivialDestructor); - Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.UserProvidedDefaultConstructor); - Record.push_back(Data.DeclaredDefaultConstructor); - Record.push_back(Data.DeclaredCopyConstructor); - Record.push_back(Data.DeclaredMoveConstructor); - Record.push_back(Data.DeclaredCopyAssignment); - Record.push_back(Data.DeclaredMoveAssignment); - Record.push_back(Data.DeclaredDestructor); + Record.push_back(Data.DeclaredSpecialMembers); Record.push_back(Data.ImplicitCopyConstructorHasConstParam); Record.push_back(Data.ImplicitCopyAssignmentHasConstParam); Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam); -- 2.7.4