diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-09-28 20:38:10 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-09-28 20:38:10 +0000 |
commit | 2cf9d656f6283f2a8be0549da110d7cfbb1ea4b2 (patch) | |
tree | cbcb070593bb170ec3e7aae8bc617367ecb6e5e3 | |
parent | b3737e4fcddbf1c3126eb853c0e3b366b35ceaba (diff) |
Centralize the management of CXXRecordDecl::DefinitionData's Empty bit
in CXXRecordDecl itself. Yes, this is also part of <rdar://problem/8459981>.
This reinstates r114924, with one crucial bug fix: we were ignoring
the implicit fields created by anonymous structs/unions when updating
the bits in CXXRecordDecl, which means that a class/struct containing
only an anonymous class/struct would be considered "empty". Hilarity
follows.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114980 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 4 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 10 | ||||
-rw-r--r-- | test/SemaCXX/type-traits.cpp | 12 |
6 files changed, 51 insertions, 30 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index aa2ff3c43d..26020ba6c4 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -704,9 +704,6 @@ public: /// a check for union-ness. bool isEmpty() const { return data().Empty; } - /// Set whether this class is empty (C++0x [meta.unary.prop]) - void setEmpty(bool Emp) { data().Empty = Emp; } - /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. bool isPolymorphic() const { return data().Polymorphic; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fdeac1ebf8..57780ef981 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3138,10 +3138,6 @@ QualType ASTContext::getObjCFastEnumerationStateType() { Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - if (getLangOptions().CPlusPlus) - if (CXXRecordDecl *CXXRD = - dyn_cast<CXXRecordDecl>(ObjCFastEnumerationStateTypeDecl)) - CXXRD->setEmpty(false); ObjCFastEnumerationStateTypeDecl->completeDefinition(); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 440eaddb7c..0e37bc7801 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -105,6 +105,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // A POD-struct is an aggregate class... data().PlainOldData = false; + // A class with a non-empty base class is not empty. + // FIXME: Standard ref? + if (!BaseClassDecl->isEmpty()) + data().Empty = false; + // Now go through all virtual bases of this base and add them. for (CXXRecordDecl::base_class_iterator VBase = BaseClassDecl->vbases_begin(), @@ -118,8 +123,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) VBases.push_back(Base); + + // C++0x [meta.unary.prop] is_empty: + // T is a class type, but not a union type, with ... no virtual base + // classes + data().Empty = false; } - } if (VBases.empty()) @@ -285,6 +294,10 @@ CXXRecordDecl::addedMember(Decl *D) { // C++ [class]p4: // A POD-struct is an aggregate class... data().PlainOldData = false; + + // Virtual functions make the class non-empty. + // FIXME: Standard ref? + data().Empty = false; } } @@ -298,18 +311,24 @@ CXXRecordDecl::addedMember(Decl *D) { // declared it. else if (Constructor->isCopyConstructor()) data().DeclaredCopyConstructor = true; - } else if (isa<CXXDestructorDecl>(D)) { + return; + } + + if (isa<CXXDestructorDecl>(D)) { data().DeclaredDestructor = true; - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + return; + } + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { // If this is the implicit copy constructor, note that we have now // declared it. // FIXME: Move constructors if (Method->getOverloadedOperator() == OO_Equal) data().DeclaredCopyAssignment = true; + return; } - - // Nothing else to do for implicitly-declared members. - return; + + // Any other implicit declarations are handled like normal declarations. } // Handle (user-declared) constructors. @@ -429,6 +448,19 @@ CXXRecordDecl::addedMember(Decl *D) { QualType T = Context.getBaseElementType(Field->getType()); if (!T->isPODType()) data().PlainOldData = false; + + // If this is not a zero-length bit-field, then the class is not empty. + if (data().Empty) { + if (!Field->getBitWidth()) + data().Empty = false; + else if (!Field->getBitWidth()->isTypeDependent() && + !Field->getBitWidth()->isValueDependent()) { + llvm::APSInt Bits; + if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context)) + if (!!Bits) + data().Empty = false; + } + } } } @@ -614,7 +646,6 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) { Method->setVirtualAsWritten(true); - setEmpty(false); setPolymorphic(true); setHasTrivialConstructor(false); setHasTrivialCopyConstructor(false); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5ac6f618d3..e6e4420f23 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1958,11 +1958,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS); - if (getLangOptions().CPlusPlus) { + if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); - if (!cast<CXXRecordDecl>(Record)->isEmpty()) - cast<CXXRecordDecl>(OwningClass)->setEmpty(false); - } } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && @@ -6190,8 +6187,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && getLangOptions().CPlusPlus) { CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); - if (!ZeroWidth) - CXXRecord->setEmpty(false); if (T->isReferenceType()) CXXRecord->setHasTrivialConstructor(false); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8ecf047a67..c9a19dd625 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -516,11 +516,6 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, const CXXRecordDecl *BaseClass, bool BaseIsVirtual) { - // A class with a non-empty base class is not empty. - // FIXME: Standard ref? - if (!BaseClass->isEmpty()) - Class->setEmpty(false); - // C++ [class.virtual]p1: // A class that [...] inherits a virtual function is called a polymorphic // class. @@ -540,11 +535,6 @@ void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, // A copy assignment operator is trivial if its class has no virtual // base classes. Class->setHasTrivialCopyAssignment(false); - - // C++0x [meta.unary.prop] is_empty: - // T is a class type, but not a union type, with ... no virtual base - // classes - Class->setEmpty(false); } else { // C++ [class.ctor]p5: // A constructor is trivial if all the direct base classes of its diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 9328326b1a..d75fd6644f 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -20,6 +20,13 @@ struct HasOp { void operator *(); }; struct HasConv { operator int(); }; struct HasAssign { void operator =(int); }; +struct HasAnonymousUnion { + union { + int i; + float f; + }; +}; + // Not PODs typedef const void cvoid; struct Derives : POD {}; @@ -84,6 +91,7 @@ void is_pod() int t12[T(__is_pod(HasConv))]; int t13[T(__is_pod(HasAssign))]; int t14[T(__is_pod(IntArNB))]; + int t15[T(__is_pod(HasAnonymousUnion))]; int t21[F(__is_pod(Derives))]; int t22[F(__is_pod(HasCons))]; @@ -131,6 +139,7 @@ void is_empty() int t27[F(__is_empty(BitOnly))]; int t28[F(__is_empty(void))]; int t29[F(__is_empty(IntArNB))]; + int t30[F(__is_empty(HasAnonymousUnion))]; // int t27[F(__is_empty(DerivesVirt))]; } @@ -141,6 +150,7 @@ void is_class() int t01[T(__is_class(Derives))]; int t02[T(__is_class(HasPriv))]; int t03[T(__is_class(ClassType))]; + int t04[T(__is_class(HasAnonymousUnion))]; int t11[F(__is_class(int))]; int t12[F(__is_class(Enum))]; @@ -167,6 +177,7 @@ void is_union() int t15[F(__is_union(UnionAr))]; int t16[F(__is_union(cvoid))]; int t17[F(__is_union(IntArNB))]; + int t18[F(__is_union(HasAnonymousUnion))]; } typedef Enum EnumType; @@ -185,6 +196,7 @@ void is_enum() int t17[F(__is_enum(ClassType))]; int t18[F(__is_enum(cvoid))]; int t19[F(__is_enum(IntArNB))]; + int t20[F(__is_enum(HasAnonymousUnion))]; } typedef HasVirt Polymorph; |