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());
}