[cfe-commits] r79143 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/ExprCXX.cpp lib/Parse/ParseExpr.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/type-traits.cpp

Eli Friedman eli.friedman at gmail.com
Sat Aug 15 14:55:26 PDT 2009


Author: efriedma
Date: Sat Aug 15 16:55:26 2009
New Revision: 79143

URL: http://llvm.org/viewvc/llvm-project?rev=79143&view=rev
Log:
Implement __is_empty.  Patch by Sean Hunt.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaCXX/type-traits.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Aug 15 16:55:26 2009
@@ -290,6 +290,12 @@
   /// PlainOldData - True when this class is a POD-type.
   bool PlainOldData : 1;
 
+  /// Empty - true when this class is empty for traits purposes, i.e. has no
+  /// data members other than 0-width bit-fields, has no virtual function/base,
+  /// and doesn't inherit from a non-empty class. Doesn't take union-ness into
+  /// account.
+  bool Empty : 1;
+
   /// Polymorphic - True when this class is polymorphic, i.e. has at least one
   /// virtual member or derives from a polymorphic class.
   bool Polymorphic : 1;
@@ -297,7 +303,7 @@
   /// Abstract - True when this class is abstract, i.e. has at least one
   /// pure virtual function, (that can come from a base class).
   bool Abstract : 1;
-  
+
   /// HasTrivialConstructor - True when this class has a trivial constructor.
   ///
   /// C++ [class.ctor]p5.  A constructor is trivial if it is an
@@ -570,6 +576,15 @@
   /// setPOD - Set whether this class is a POD-type (C++ [class]p4).
   void setPOD(bool POD) { PlainOldData = POD; }
 
+  /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
+  /// means it has a virtual function, virtual base, data member (other than
+  /// 0-width bit-field) or inherits from a non-empty class. Does NOT include
+  /// a check for union-ness.
+  bool isEmpty() const { return Empty; }
+
+  /// Set whether this class is empty (C++0x [meta.unary.prop])
+  void setEmpty(bool Emp) { 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 Polymorphic; }

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Sat Aug 15 16:55:26 2009
@@ -223,6 +223,12 @@
     if (const RecordType *RT = QueriedType->getAs<RecordType>())
       return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
     return false;
+  case UTT_IsEmpty:
+    if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
+      return !Record->getDecl()->isUnion()
+          && cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
+    }
+    return false;
   case UTT_HasTrivialConstructor:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
     //   If __is_pod (type) is true then the trait is true, else if type is

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Sat Aug 15 16:55:26 2009
@@ -815,6 +815,7 @@
   case tok::kw___is_class:
   case tok::kw___is_enum:
   case tok::kw___is_union:
+  case tok::kw___is_empty:
   case tok::kw___is_polymorphic:
   case tok::kw___is_abstract:
   case tok::kw___has_trivial_constructor:

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Aug 15 16:55:26 2009
@@ -3324,8 +3324,10 @@
   /// VerifyBitField - verifies that a bit field expression is an ICE and has
   /// the correct width, and that the field type is valid. 
   /// Returns false on success.
+  /// Can optionally return whether the bit-field is of width 0
   bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, 
-                      QualType FieldTy, const Expr *BitWidth);
+                      QualType FieldTy, const Expr *BitWidth, 
+                      bool *ZeroWidth = 0);
 
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Aug 15 16:55:26 2009
@@ -2536,6 +2536,7 @@
       CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
       CurClass->setAggregate(false);
       CurClass->setPOD(false);
+      CurClass->setEmpty(false);
       CurClass->setPolymorphic(true);
       CurClass->setHasTrivialConstructor(false);
       CurClass->setHasTrivialCopyConstructor(false);
@@ -4331,8 +4332,12 @@
 
 // Note that FieldName may be null for anonymous bitfields.
 bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, 
-                          QualType FieldTy, const Expr *BitWidth) {
-  
+                          QualType FieldTy, const Expr *BitWidth,
+                          bool *ZeroWidth) {
+  // Default to true; that shouldn't confuse checks for emptiness
+  if (ZeroWidth)
+    *ZeroWidth = true;
+
   // C99 6.7.2.1p4 - verify the field type.
   // C++ 9.6p3: A bit-field shall have integral or enumeration type.
   if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) {
@@ -4355,6 +4360,9 @@
   if (VerifyIntegerConstantExpression(BitWidth, &Value))
     return true;
 
+  if (Value != 0 && ZeroWidth)
+    *ZeroWidth = false;
+
   // Zero-width bitfield is ok for anonymous field.
   if (Value == 0 && FieldName)
     return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName;
@@ -4490,11 +4498,13 @@
                              AbstractFieldType))
     InvalidDecl = true;
   
+  bool ZeroWidth = false;
   // If this is declared as a bit-field, check the bit-field.
-  if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) {
+  if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
     InvalidDecl = true;
     DeleteExpr(BitWidth);
     BitWidth = 0;
+    ZeroWidth = false;
   }
   
   FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth,
@@ -4511,17 +4521,24 @@
   if (getLangOptions().CPlusPlus) {
     QualType EltTy = Context.getBaseElementType(T);
 
+    CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
+
+    if (!T->isPODType())
+      CXXRecord->setPOD(false);
+    if (!ZeroWidth)
+      CXXRecord->setEmpty(false);
+
     if (const RecordType *RT = EltTy->getAs<RecordType>()) {
       CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
 
       if (!RDecl->hasTrivialConstructor())
-        cast<CXXRecordDecl>(Record)->setHasTrivialConstructor(false);
+        CXXRecord->setHasTrivialConstructor(false);
       if (!RDecl->hasTrivialCopyConstructor())
-        cast<CXXRecordDecl>(Record)->setHasTrivialCopyConstructor(false);
+        CXXRecord->setHasTrivialCopyConstructor(false);
       if (!RDecl->hasTrivialCopyAssignment())
-        cast<CXXRecordDecl>(Record)->setHasTrivialCopyAssignment(false);
+        CXXRecord->setHasTrivialCopyAssignment(false);
       if (!RDecl->hasTrivialDestructor())
-        cast<CXXRecordDecl>(Record)->setHasTrivialDestructor(false);
+        CXXRecord->setHasTrivialDestructor(false);
 
       // C++ 9.5p1: An object of a class with a non-trivial
       // constructor, a non-trivial copy constructor, a non-trivial
@@ -4557,9 +4574,6 @@
     }
   }
 
-  if (getLangOptions().CPlusPlus && !T->isPODType())
-    cast<CXXRecordDecl>(Record)->setPOD(false);
-
   // FIXME: We need to pass in the attributes given an AST
   // representation, not a parser representation.
   if (D)

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Aug 15 16:55:26 2009
@@ -383,12 +383,16 @@
                           SpecifierRange))
     return 0;
 
-  // If the base class is polymorphic, the new one is, too.
+  // If the base class is polymorphic or isn't empty, the new one is/isn't, too.
   RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
   assert(BaseDecl && "Record type has no declaration");
   BaseDecl = BaseDecl->getDefinition(Context);
   assert(BaseDecl && "Base type is not incomplete, but has no definition");
-  if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
+  CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
+  assert(CXXBaseDecl && "Base type is not a C++ type");
+  if (!CXXBaseDecl->isEmpty())
+    Class->setEmpty(false);
+  if (CXXBaseDecl->isPolymorphic())
     Class->setPolymorphic(true);
 
   // C++ [dcl.init.aggr]p1:
@@ -409,6 +413,11 @@
     //   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 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Aug 15 16:55:26 2009
@@ -749,6 +749,7 @@
     New->setVirtualAsWritten(true);
     Record->setAggregate(false);
     Record->setPOD(false);
+    Record->setEmpty(false);
     Record->setPolymorphic(true);
   }
   if (Tmpl->isPure()) {

Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=79143&r1=79142&r2=79143&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Sat Aug 15 16:55:26 2009
@@ -7,14 +7,23 @@
 // PODs
 enum Enum { EV };
 struct POD { Enum e; int i; float f; NonPOD* p; };
+struct Empty {};
+typedef Empty EmptyAr[10];
 typedef int Int;
 typedef Int IntAr[10];
 class Statics { static int priv; static NonPOD np; };
+union EmptyUnion {};
+union Union { int i; float f; };
+struct HasFunc { void f (); };
+struct HasOp { void operator *(); };
+struct HasConv { operator int(); };
+struct HasAssign { void operator =(int); };
 
 // Not PODs
 struct Derives : POD {};
+struct DerivesEmpty : Empty {};
 struct HasCons { HasCons(int); };
-struct HasAssign { HasAssign operator =(const HasAssign&); };
+struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
 struct HasDest { ~HasDest(); };
 class  HasPriv { int priv; };
 class  HasProt { protected: int prot; };
@@ -23,6 +32,7 @@
 struct HasVirt { virtual void Virt() {}; };
 typedef Derives NonPODAr[10];
 typedef HasVirt VirtAr[10];
+union NonPODUnion { int i; Derives n; };
 
 void is_pod()
 {
@@ -32,10 +42,17 @@
   int t04[T(__is_pod(Int))];
   int t05[T(__is_pod(IntAr))];
   int t06[T(__is_pod(Statics))];
+  int t07[T(__is_pod(Empty))];
+  int t08[T(__is_pod(EmptyUnion))];
+  int t09[T(__is_pod(Union))];
+  int t10[T(__is_pod(HasFunc))];
+  int t11[T(__is_pod(HasOp))];
+  int t12[T(__is_pod(HasConv))];
+  int t13[T(__is_pod(HasAssign))];
 
   int t21[F(__is_pod(Derives))];
   int t22[F(__is_pod(HasCons))];
-  int t23[F(__is_pod(HasAssign))];
+  int t23[F(__is_pod(HasCopyAssign))];
   int t24[F(__is_pod(HasDest))];
   int t25[F(__is_pod(HasPriv))];
   int t26[F(__is_pod(HasProt))];
@@ -43,9 +60,40 @@
   int t28[F(__is_pod(HasNonPOD))];
   int t29[F(__is_pod(HasVirt))];
   int t30[F(__is_pod(NonPODAr))];
+  int t31[F(__is_pod(DerivesEmpty))];
+ // int t32[F(__is_pod(NonPODUnion))];
+}
+
+typedef Empty EmptyAr[10];
+struct Bit0 { int : 0; };
+struct Bit0Cons { int : 0; Bit0Cons(); };
+struct BitOnly { int x : 3; };
+//struct DerivesVirt : virtual POD {};
+
+void is_empty()
+{
+  int t01[T(__is_empty(Empty))];
+  int t02[T(__is_empty(DerivesEmpty))];
+  int t03[T(__is_empty(HasCons))];
+  int t04[T(__is_empty(HasCopyAssign))];
+  int t05[T(__is_empty(HasDest))];
+  int t06[T(__is_empty(HasFunc))];
+  int t07[T(__is_empty(HasOp))];
+  int t08[T(__is_empty(HasConv))];
+  int t09[T(__is_empty(HasAssign))];
+  int t10[T(__is_empty(Bit0))];
+  int t11[T(__is_empty(Bit0Cons))];
+
+  int t21[F(__is_empty(Int))];
+  int t22[F(__is_empty(POD))];
+  int t23[F(__is_empty(EmptyUnion))];
+  int t24[F(__is_empty(EmptyAr))];
+  int t25[F(__is_empty(HasRef))];
+  int t26[F(__is_empty(HasVirt))];
+  int t27[F(__is_empty(BitOnly))];
+//  int t27[F(__is_empty(DerivesVirt))];
 }
 
-union Union { int i; float f; };
 typedef Derives ClassType;
 
 void is_class()
@@ -93,7 +141,7 @@
   int t17[F(__is_enum(ClassType))];
 }
 
-struct Polymorph { virtual void f(); };
+typedef HasVirt Polymorph;
 struct InheritPolymorph : Polymorph {};
 
 void is_polymorphic()
@@ -134,7 +182,7 @@
   int t12[F(__has_trivial_constructor(HasRef))];
   int t13[F(__has_trivial_constructor(HasCopy))];
   int t14[F(__has_trivial_constructor(IntRef))];
-  int t15[T(__has_trivial_constructor(HasAssign))];
+  int t15[T(__has_trivial_constructor(HasCopyAssign))];
   int t16[T(__has_trivial_constructor(const Int))];
   int t17[T(__has_trivial_constructor(NonPODAr))];
   int t18[F(__has_trivial_constructor(VirtAr))];
@@ -155,7 +203,7 @@
   int t12[T(__has_trivial_copy(HasRef))];
   int t13[F(__has_trivial_copy(HasCopy))];
   int t14[T(__has_trivial_copy(IntRef))];
-  int t15[T(__has_trivial_copy(HasAssign))];
+  int t15[T(__has_trivial_copy(HasCopyAssign))];
   int t16[T(__has_trivial_copy(const Int))];
   int t17[F(__has_trivial_copy(NonPODAr))];
   int t18[F(__has_trivial_copy(VirtAr))];
@@ -176,7 +224,7 @@
   int t12[T(__has_trivial_assign(HasRef))];
   int t13[T(__has_trivial_assign(HasCopy))];
   int t14[F(__has_trivial_assign(IntRef))];
-  int t15[F(__has_trivial_assign(HasAssign))];
+  int t15[F(__has_trivial_assign(HasCopyAssign))];
   int t16[F(__has_trivial_assign(const Int))];
   int t17[F(__has_trivial_assign(NonPODAr))];
   int t18[F(__has_trivial_assign(VirtAr))];
@@ -197,7 +245,7 @@
   int t12[T(__has_trivial_destructor(HasRef))];
   int t13[T(__has_trivial_destructor(HasCopy))];
   int t14[T(__has_trivial_destructor(IntRef))];
-  int t15[T(__has_trivial_destructor(HasAssign))];
+  int t15[T(__has_trivial_destructor(HasCopyAssign))];
   int t16[T(__has_trivial_destructor(const Int))];
   int t17[T(__has_trivial_destructor(NonPODAr))];
   int t18[T(__has_trivial_destructor(VirtAr))];





More information about the cfe-commits mailing list