]> granicus.if.org Git - clang/commitdiff
Centralize the management of CXXRecordDecl::DefinitionData's Empty bit
authorDouglas Gregor <dgregor@apple.com>
Tue, 28 Sep 2010 20:38:10 +0000 (20:38 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 28 Sep 2010 20:38:10 +0000 (20:38 +0000)
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

include/clang/AST/DeclCXX.h
lib/AST/ASTContext.cpp
lib/AST/DeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/type-traits.cpp

index aa2ff3c43df6374259f4c33f4fb5051221badcbe..26020ba6c45046914a41cfc5c93717b6d18f9ca2 100644 (file)
@@ -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; }
index fdeac1ebf87b3cea9cefa705442979dd8694a622..57780ef981cd742a9088e4d4380567c9b8da44a6 100644 (file)
@@ -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();
   }
index 440eaddb7c160160d8765aff70599beea980dd17..0e37bc7801ceee17c5393e1eab83dee764addcdc 100644 (file)
@@ -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);
index 5ac6f618d302ea7da7f44c3362d9982d208e6530..e6e4420f23bafcfd33520582ec3d52c393a57cb4 100644 (file)
@@ -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);
 
index 8ecf047a670d363f8d7b04c2c8be7d4363456d13..c9a19dd6258acf1abb74d406eccac341e27bbb0b 100644 (file)
@@ -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
index 9328326b1a548e68c6461e8b2c5eb31704586a6f..d75fd6644f74d89ebf3db01ad2d4e2d784460847 100644 (file)
@@ -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;