Refactor to reduce duplication in handling of special member functions. No functionality change.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168977 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a3c0bab..ba87764 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -36,26 +36,19 @@
}
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 @@
// 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 @@
// -- 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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<CXXConstructorDecl>(D)) {
if (!Constructor->isImplicit()) {
@@ -579,45 +551,23 @@
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 @@
if (getASTContext().getLangOpts().CPlusPlus0x
? UserProvided : !Constructor->isImplicit())
data().Aggregate = false;
-
- return;
}
// Handle destructors.
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(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<CXXMethodDecl>(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<ReferenceType>();
@@ -692,34 +610,16 @@
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<CXXConversionDecl>(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 @@
}
}
+ 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<FieldDecl>(D)) {
// C++ [class.bit]p2:
@@ -796,7 +727,7 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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;
}