t/clang/type-traits

Patch authored by John Wiegley.

These type traits are used for parsing code that employs certain features of
the Embarcadero C++ compiler.  Several of these constructs are also desired by
libc++, according to its project pages (such as __is_standard_layout).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130342 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a71750b..7ab6030 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -926,6 +926,10 @@
 
 void CXXRecordDecl::completeDefinition() {
   completeDefinition(0);
+
+  ASTContext &Context = getASTContext();
+  if (const RecordType *RT = getTypeForDecl()->getAs<RecordType>())
+    data().HasStandardLayout = RT->hasStandardLayout(Context);
 }
 
 void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index cf42e63..b96591b 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1251,23 +1251,48 @@
 
 static const char *getTypeTraitName(UnaryTypeTrait UTT) {
   switch (UTT) {
-  default: llvm_unreachable("Unknown unary type trait");
+  default: assert(false && "Unknown type trait");
   case UTT_HasNothrowAssign:      return "__has_nothrow_assign";
-  case UTT_HasNothrowCopy:        return "__has_nothrow_copy";
   case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
+  case UTT_HasNothrowCopy:          return "__has_nothrow_copy";
   case UTT_HasTrivialAssign:      return "__has_trivial_assign";
-  case UTT_HasTrivialCopy:        return "__has_trivial_copy";
   case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+  case UTT_HasTrivialCopy:          return "__has_trivial_copy";
   case UTT_HasTrivialDestructor:  return "__has_trivial_destructor";
   case UTT_HasVirtualDestructor:  return "__has_virtual_destructor";
   case UTT_IsAbstract:            return "__is_abstract";
+  case UTT_IsArithmetic:            return "__is_arithmetic";
+  case UTT_IsArray:                 return "__is_array";
   case UTT_IsClass:               return "__is_class";
+  case UTT_IsCompleteType:          return "__is_complete_type";
+  case UTT_IsCompound:              return "__is_compound";
+  case UTT_IsConst:                 return "__is_const";
   case UTT_IsEmpty:               return "__is_empty";
   case UTT_IsEnum:                return "__is_enum";
+  case UTT_IsFloatingPoint:         return "__is_floating_point";
+  case UTT_IsFunction:              return "__is_function";
+  case UTT_IsFundamental:           return "__is_fundamental";
+  case UTT_IsIntegral:              return "__is_integral";
+  case UTT_IsLvalueExpr:            return "__is_lvalue_expr";
+  case UTT_IsLvalueReference:       return "__is_lvalue_reference";
+  case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
+  case UTT_IsMemberObjectPointer:   return "__is_member_object_pointer";
+  case UTT_IsMemberPointer:         return "__is_member_pointer";
+  case UTT_IsObject:                return "__is_object";
   case UTT_IsPOD:                 return "__is_pod";
+  case UTT_IsPointer:               return "__is_pointer";
   case UTT_IsPolymorphic:         return "__is_polymorphic";
-  case UTT_IsTrivial:             return "__is_trivial";
+  case UTT_IsReference:             return "__is_reference";
+  case UTT_IsRvalueExpr:            return "__is_rvalue_expr";
+  case UTT_IsRvalueReference:       return "__is_rvalue_reference";
+  case UTT_IsScalar:                return "__is_scalar";
+  case UTT_IsSigned:                return "__is_signed";
+  case UTT_IsStandardLayout:        return "__is_standard_layout";
+  case UTT_IsTrivial:               return "__is_trivial";
   case UTT_IsUnion:               return "__is_union";
+  case UTT_IsUnsigned:              return "__is_unsigned";
+  case UTT_IsVoid:                  return "__is_void";
+  case UTT_IsVolatile:              return "__is_volatile";
   }
   return "";
 }
@@ -1275,6 +1300,8 @@
 static const char *getTypeTraitName(BinaryTypeTrait BTT) {
   switch (BTT) {
   case BTT_IsBaseOf:         return "__is_base_of";
+  case BTT_IsConvertible:    return "__is_convertible";
+  case BTT_IsSame:           return "__is_same";
   case BTT_TypeCompatible:   return "__builtin_types_compatible_p";
   case BTT_IsConvertibleTo:  return "__is_convertible_to";
   }
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index d43a121..e75ce7d 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1385,6 +1385,109 @@
   return isa<RecordDecl>(TT->getDecl());
 }
 
+static uint64_t countBasesWithFields(QualType BaseType) {
+  uint64_t BasesWithFields = 0;
+  if (const RecordType *T = BaseType->getAs<RecordType>()) {
+    CXXRecordDecl *RD = cast<CXXRecordDecl>(T->getDecl());
+    for (CXXRecordDecl::field_iterator Field = RD->field_begin(),
+           E = RD->field_end(); Field != E; ++Field)
+      BasesWithFields = 1;
+    for (CXXRecordDecl::base_class_const_iterator B = RD->bases_begin(),
+           BE = RD->bases_end(); B != BE; ++B)
+      BasesWithFields += countBasesWithFields(B->getType());
+  }
+  return BasesWithFields;
+}
+
+bool RecordType::hasStandardLayout(ASTContext& Context) const {
+  CXXRecordDecl *RD = cast<CXXRecordDecl>(getDecl());
+  if (! RD) {
+    assert(cast<RecordDecl>(getDecl()) &&
+           "RecordType does not have a corresponding RecordDecl");
+    return true;
+  }
+
+  // A standard-layout class is a class that:
+
+  for (CXXRecordDecl::method_iterator M = RD->method_begin(), 
+       ME = RD->method_end(); M != ME; ++M) {
+    CXXMethodDecl *Method = *M;
+
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- has no virtual functions (10.3) [...]
+    if (Method->isVirtual())
+      return false;
+  }
+
+  AccessSpecifier AS = AS_none;
+  QualType FirstFieldType;
+  bool FirstFieldType_set = false;
+  uint64_t FieldCount = 0;
+
+  for (CXXRecordDecl::field_iterator Field = RD->field_begin(),
+         E = RD->field_end(); Field != E; ++Field, ++FieldCount) {
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- has no non-static data members of type non-standard-layout class
+    //       (or array of such types) or reference [...]
+    QualType FieldType = Context.getBaseElementType((*Field)->getType());
+    if (const RecordType *T =
+        Context.getBaseElementType(FieldType)->getAs<RecordType>()) {
+      if (! T->hasStandardLayout(Context) || T->isReferenceType())
+        return false;
+    }
+    if (! FirstFieldType_set) {
+      FirstFieldType = FieldType;
+      FirstFieldType_set = true;
+    }
+  
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- has the same access control (Clause 11) for all non-static data
+    //       members [...]
+    if (AS == AS_none)
+      AS = (*Field)->getAccess();
+    else if (AS != (*Field)->getAccess())
+      return false;
+  }
+
+  for (CXXRecordDecl::base_class_const_iterator B = RD->bases_begin(),
+           BE = RD->bases_end(); B != BE; ++B) {
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- no virtual base classes (10.1) [...]
+    if (B->isVirtual())
+      return false;
+
+    QualType BT = B->getType();
+
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- has no non-standard-layout base classes [...]
+    if (const RecordType *T = BT->getAs<RecordType>())
+      if (! T->hasStandardLayout(Context))
+        return false;
+
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- has no base classes of the same type as the first non-static data
+    //       member.
+    if (BT == FirstFieldType)
+      return false;
+
+    // C++0x [class]p7:
+    //   A standard-layout class is a class that [...]
+    //    -- either has no non-static data members in the most derived class
+    //       and at most one base class with non-static data members, or has
+    //       no base classes with non-static data members [...]
+    if (countBasesWithFields(BT) > (FieldCount == 0 ? 1 : 0))
+      return false;
+  }
+
+  return true;
+}
+
 bool EnumType::classof(const TagType *TT) {
   return isa<EnumDecl>(TT->getDecl());
 }