aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@boostpro.com>2011-04-27 23:09:49 +0000
committerJohn Wiegley <johnw@boostpro.com>2011-04-27 23:09:49 +0000
commit20c0da7787c9a7d2529e42a4a91d777778595d74 (patch)
tree6a2b639e6c63fb98bf612c1ab9f3ac8512653bc6
parent26517e4ffe7c2c366496feb02370ba24ab5ae8f5 (diff)
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
-rw-r--r--include/clang/AST/DeclCXX.h19
-rw-r--r--include/clang/AST/Type.h5
-rw-r--r--include/clang/Basic/TokenKinds.def29
-rw-r--r--include/clang/Basic/TypeTraits.h33
-rw-r--r--lib/AST/DeclCXX.cpp4
-rw-r--r--lib/AST/StmtPrinter.cpp35
-rw-r--r--lib/AST/Type.cpp103
-rw-r--r--lib/Parse/ParseDeclCXX.cpp29
-rw-r--r--lib/Parse/ParseExpr.cpp55
-rw-r--r--lib/Parse/ParseExprCXX.cpp35
-rw-r--r--lib/Sema/SemaExprCXX.cpp81
-rw-r--r--test/CodeGenCXX/mangle.cpp20
-rw-r--r--test/SemaCXX/type-traits.cpp825
13 files changed, 1231 insertions, 42 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index f41a7d617e..bc1e018b4f 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -306,6 +306,21 @@ class CXXRecordDecl : public RecordDecl {
/// one pure virtual function, (that can come from a base class).
bool Abstract : 1;
+ /// HasStandardLayout - True when this class has standard layout.
+ ///
+ /// 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,
+ /// * has no virtual functions (10.3) and no virtual base classes (10.1),
+ /// * has the same access control (Clause 11) for all non-static data members
+ /// * has no non-standard-layout base classes,
+ /// * 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, and
+ /// * has no base classes of the same type as the first non-static data
+ /// member.
+ bool HasStandardLayout : 1;
+
/// HasTrivialConstructor - True when this class has a trivial constructor.
///
/// C++ [class.ctor]p5. A constructor is trivial if it is an
@@ -765,6 +780,10 @@ public:
/// which means that the class contains or inherits a pure virtual function.
bool isAbstract() const { return data().Abstract; }
+ // hasStandardLayout - Whether this class has standard layout
+ // (C++ [class]p7)
+ bool hasStandardLayout() const { return data().HasStandardLayout; }
+
// hasTrivialConstructor - Whether this class has a trivial constructor
// (C++ [class.ctor]p5)
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index cfdfae1ee3..9fa301e4aa 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1171,7 +1171,7 @@ public:
/// (C++0x [basic.types]p10)
bool isLiteralType() const;
- /// isTrivialType - Return true if this is a literal type
+ /// isTrivialType - Return true if this is a trivial type
/// (C++0x [basic.types]p9)
bool isTrivialType() const;
@@ -2832,6 +2832,9 @@ public:
// const, it needs to return false.
bool hasConstFields() const { return false; }
+ /// \brief Whether this class has standard layout
+ bool hasStandardLayout(ASTContext& Ctx) const;
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index eefa9c02a6..e66922eaa2 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -350,6 +350,35 @@ KEYWORD(__is_union , KEYCXX)
KEYWORD(__is_lvalue_expr , KEYCXX)
KEYWORD(__is_rvalue_expr , KEYCXX)
+// Embarcadero Unary Type Traits
+KEYWORD(__is_arithmetic , KEYCXX)
+KEYWORD(__is_floating_point , KEYCXX)
+KEYWORD(__is_integral , KEYCXX)
+KEYWORD(__is_complete_type , KEYCXX)
+KEYWORD(__is_void , KEYCXX)
+KEYWORD(__is_array , KEYCXX)
+KEYWORD(__is_function , KEYCXX)
+KEYWORD(__is_reference , KEYCXX)
+KEYWORD(__is_lvalue_reference , KEYCXX)
+KEYWORD(__is_rvalue_reference , KEYCXX)
+KEYWORD(__is_fundamental , KEYCXX)
+KEYWORD(__is_object , KEYCXX)
+KEYWORD(__is_scalar , KEYCXX)
+KEYWORD(__is_compound , KEYCXX)
+KEYWORD(__is_pointer , KEYCXX)
+KEYWORD(__is_member_object_pointer , KEYCXX)
+KEYWORD(__is_member_function_pointer, KEYCXX)
+KEYWORD(__is_member_pointer , KEYCXX)
+KEYWORD(__is_const , KEYCXX)
+KEYWORD(__is_volatile , KEYCXX)
+KEYWORD(__is_standard_layout , KEYCXX)
+KEYWORD(__is_signed , KEYCXX)
+KEYWORD(__is_unsigned , KEYCXX)
+
+// Embarcadero Binary Type Traits
+KEYWORD(__is_same , KEYCXX)
+KEYWORD(__is_convertible , KEYCXX)
+
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 5883efe3bb..6ba1bbdeee 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -27,21 +27,48 @@ namespace clang {
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
+ UTT_IsArithmetic,
+ UTT_IsArray,
UTT_IsClass,
+ UTT_IsCompleteType,
+ UTT_IsCompound,
+ UTT_IsConst,
UTT_IsEmpty,
UTT_IsEnum,
+ UTT_IsFloatingPoint,
+ UTT_IsFunction,
+ UTT_IsFundamental,
+ UTT_IsIntegral,
UTT_IsLiteral,
+ UTT_IsLvalueExpr,
+ UTT_IsLvalueReference,
+ UTT_IsMemberFunctionPointer,
+ UTT_IsMemberObjectPointer,
+ UTT_IsMemberPointer,
+ UTT_IsObject,
UTT_IsPOD,
+ UTT_IsPointer,
UTT_IsPolymorphic,
+ UTT_IsReference,
+ UTT_IsRvalueExpr,
+ UTT_IsRvalueReference,
+ UTT_IsScalar,
+ UTT_IsSigned,
+ UTT_IsStandardLayout,
UTT_IsTrivial,
- UTT_IsUnion
+ UTT_IsUnion,
+ UTT_IsUnsigned,
+ UTT_IsVoid,
+ UTT_IsVolatile
};
/// BinaryTypeTrait - Names for the binary type traits.
enum BinaryTypeTrait {
BTT_IsBaseOf,
- BTT_TypeCompatible,
- BTT_IsConvertibleTo
+ BTT_IsConvertible,
+ BTT_IsConvertibleTo,
+ BTT_IsSame,
+ BTT_TypeCompatible
};
/// UnaryExprOrTypeTrait - Names for the "expression or type" traits.
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a71750bb4c..7ab60303ad 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -926,6 +926,10 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
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 cf42e63379..b96591b661 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1251,23 +1251,48 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
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(UnaryTypeTrait UTT) {
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 d43a121881..e75ce7dfe4 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1385,6 +1385,109 @@ bool RecordType::classof(const TagType *TT) {
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());
}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f59302868b..c41798e35e 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -731,22 +731,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// styles of attributes?
MaybeParseCXX0XAttributes(attrs);
- if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
- // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
- // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the
- // token sequence "struct __is_pod", make __is_pod into a normal
- // identifier rather than a keyword, to allow libstdc++ 4.2 to work
- // properly.
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
- Tok.setKind(tok::identifier);
- }
-
- if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) {
- // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but
- // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the
- // token sequence "struct __is_empty", make __is_empty into a normal
- // identifier rather than a keyword, to allow libstdc++ 4.2 to work
- // properly.
+ if (TagType == DeclSpec::TST_struct &&
+ (Tok.is(tok::kw___is_pod) ||
+ Tok.is(tok::kw___is_empty) ||
+ Tok.is(tok::kw___is_void) ||
+ Tok.is(tok::kw___is_pointer) ||
+ Tok.is(tok::kw___is_arithmetic) ||
+ Tok.is(tok::kw___is_fundamental) ||
+ Tok.is(tok::kw___is_scalar))) {
+ // GNU libstdc++ 4.2 uses certain intrinsic names as the name of
+ // struct templates, but these are keywords in GCC >= 4.3 and
+ // Clang. Therefore, when we see the token sequence "struct X", make
+ // X into a normal identifier rather than a keyword, to allow
+ // libstdc++ 4.2 to work properly.
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
Tok.setKind(tok::identifier);
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index c990c52e7b..1c4a942780 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -519,6 +519,34 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '::'[opt] 'delete' cast-expression
/// '::'[opt] 'delete' '[' ']' cast-expression
///
+/// [GNU/Embarcadero] unary-type-trait:
+/// '__is_arithmetic'
+/// '__is_floating_point'
+/// '__is_integral'
+/// '__is_lvalue_expr'
+/// '__is_rvalue_expr'
+/// '__is_complete_type'
+/// '__is_void'
+/// '__is_array'
+/// '__is_function'
+/// '__is_reference'
+/// '__is_lvalue_reference'
+/// '__is_rvalue_reference'
+/// '__is_fundamental'
+/// '__is_object'
+/// '__is_scalar'
+/// '__is_compound'
+/// '__is_pointer'
+/// '__is_member_object_pointer'
+/// '__is_member_function_pointer'
+/// '__is_member_pointer'
+/// '__is_const'
+/// '__is_volatile'
+/// '__is_trivial'
+/// '__is_standard_layout'
+/// '__is_signed'
+/// '__is_unsigned'
+///
/// [GNU] unary-type-trait:
/// '__has_nothrow_assign'
/// '__has_nothrow_copy'
@@ -540,6 +568,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// binary-type-trait:
/// [GNU] '__is_base_of'
/// [MS] '__is_convertible_to'
+/// '__is_convertible'
+/// '__is_same'
///
/// [Embarcadero] expression-trait:
/// '__is_lvalue_expr'
@@ -997,6 +1027,29 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_empty:
case tok::kw___is_enum:
case tok::kw___is_literal:
+ case tok::kw___is_arithmetic:
+ case tok::kw___is_integral:
+ case tok::kw___is_floating_point:
+ case tok::kw___is_complete_type:
+ case tok::kw___is_void:
+ case tok::kw___is_array:
+ case tok::kw___is_function:
+ case tok::kw___is_reference:
+ case tok::kw___is_lvalue_reference:
+ case tok::kw___is_rvalue_reference:
+ case tok::kw___is_fundamental:
+ case tok::kw___is_object:
+ case tok::kw___is_scalar:
+ case tok::kw___is_compound:
+ case tok::kw___is_pointer:
+ case tok::kw___is_member_object_pointer:
+ case tok::kw___is_member_function_pointer:
+ case tok::kw___is_member_pointer:
+ case tok::kw___is_const:
+ case tok::kw___is_volatile:
+ case tok::kw___is_standard_layout:
+ case tok::kw___is_signed:
+ case tok::kw___is_unsigned:
case tok::kw___is_literal_type:
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
@@ -1014,6 +1067,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_types_compatible_p:
case tok::kw___is_base_of:
+ case tok::kw___is_same:
+ case tok::kw___is_convertible:
case tok::kw___is_convertible_to:
return ParseBinaryTypeTrait();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 7bf76a917f..aade050df4 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1912,25 +1912,50 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
- default: llvm_unreachable("Not a known unary type trait");
+ default: assert(false && "Not a known unary type trait.");
case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
- case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
+ case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
- case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
case tok::kw___is_abstract: return UTT_IsAbstract;
+ case tok::kw___is_arithmetic: return UTT_IsArithmetic;
+ case tok::kw___is_array: return UTT_IsArray;
case tok::kw___is_class: return UTT_IsClass;
+ case tok::kw___is_complete_type: return UTT_IsCompleteType;
+ case tok::kw___is_compound: return UTT_IsCompound;
+ case tok::kw___is_const: return UTT_IsConst;
case tok::kw___is_empty: return UTT_IsEmpty;
case tok::kw___is_enum: return UTT_IsEnum;
+ case tok::kw___is_floating_point: return UTT_IsFloatingPoint;
+ case tok::kw___is_function: return UTT_IsFunction;
+ case tok::kw___is_fundamental: return UTT_IsFundamental;
+ case tok::kw___is_integral: return UTT_IsIntegral;
+ case tok::kw___is_lvalue_expr: return UTT_IsLvalueExpr;
+ case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference;
+ case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer;
+ case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer;
+ case tok::kw___is_member_pointer: return UTT_IsMemberPointer;
+ case tok::kw___is_object: return UTT_IsObject;
case tok::kw___is_literal: return UTT_IsLiteral;
case tok::kw___is_literal_type: return UTT_IsLiteral;
case tok::kw___is_pod: return UTT_IsPOD;
+ case tok::kw___is_pointer: return UTT_IsPointer;
case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
- case tok::kw___is_trivial: return UTT_IsTrivial;
+ case tok::kw___is_reference: return UTT_IsReference;
+ case tok::kw___is_rvalue_expr: return UTT_IsRvalueExpr;
+ case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference;
+ case tok::kw___is_scalar: return UTT_IsScalar;
+ case tok::kw___is_signed: return UTT_IsSigned;
+ case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
+ case tok::kw___is_trivial: return UTT_IsTrivial;
case tok::kw___is_union: return UTT_IsUnion;
+ case tok::kw___is_unsigned: return UTT_IsUnsigned;
+ case tok::kw___is_void: return UTT_IsVoid;
+ case tok::kw___is_volatile: return UTT_IsVolatile;
}
}
@@ -1938,6 +1963,8 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
default: llvm_unreachable("Not a known binary type trait");
case tok::kw___is_base_of: return BTT_IsBaseOf;
+ case tok::kw___is_convertible: return BTT_IsConvertible;
+ case tok::kw___is_same: return BTT_IsSame;
case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
case tok::kw___is_convertible_to: return BTT_IsConvertibleTo;
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index f8ad763e4b..7086176d89 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2379,6 +2379,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
return false;
case UTT_IsAbstract:
if (const RecordType *RT = T->getAs<RecordType>())
+ if (!Self.RequireCompleteType(KeyLoc, T, diag::err_incomplete_typeid))
return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
return false;
case UTT_IsEmpty:
@@ -2387,6 +2388,74 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
&& cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
}
return false;
+ case UTT_IsIntegral:
+ return T->isIntegralType(C);
+ case UTT_IsFloatingPoint:
+ return T->isFloatingType();
+ case UTT_IsArithmetic:
+ return T->isArithmeticType() && ! T->isEnumeralType();
+ case UTT_IsArray:
+ return T->isArrayType();
+ case UTT_IsCompleteType:
+ return ! T->isIncompleteType();
+ case UTT_IsCompound:
+ return ! (T->isVoidType() || T->isArithmeticType()) || T->isEnumeralType();
+ case UTT_IsConst:
+ return T.isConstQualified();
+ case UTT_IsFunction:
+ return T->isFunctionType();
+ case UTT_IsFundamental:
+ return T->isVoidType() || (T->isArithmeticType() && ! T->isEnumeralType());
+ case UTT_IsLvalueReference:
+ return T->isLValueReferenceType();
+ case UTT_IsMemberFunctionPointer:
+ return T->isMemberFunctionPointerType();
+ case UTT_IsMemberObjectPointer:
+ return T->isMemberDataPointerType();
+ case UTT_IsMemberPointer:
+ return T->isMemberPointerType();
+ case UTT_IsObject:
+ // Defined in Section 3.9 p8 of the Working Draft, essentially:
+ // !__is_reference(T) && !__is_function(T) && !__is_void(T).
+ return ! (T->isReferenceType() || T->isFunctionType() || T->isVoidType());
+ case UTT_IsPointer:
+ return T->isPointerType();
+ case UTT_IsReference:
+ return T->isReferenceType();
+ case UTT_IsRvalueReference:
+ return T->isRValueReferenceType();
+ case UTT_IsScalar:
+ // Scalar type is defined in Section 3.9 p10 of the Working Draft.
+ // Essentially:
+ // __is_arithmetic( T ) || __is_enumeration(T) ||
+ // __is_pointer(T) || __is_member_pointer(T)
+ return (T->isArithmeticType() || T->isEnumeralType() ||
+ T->isPointerType() || T->isMemberPointerType());
+ case UTT_IsSigned:
+ return T->isSignedIntegerType();
+ case UTT_IsStandardLayout:
+ // Error if T is an incomplete type.
+ if (Self.RequireCompleteType(KeyLoc, T, diag::err_incomplete_typeid))
+ return false;
+
+ // A standard layout type is:
+ // - a scalar type
+ // - an array of standard layout types
+ // - a standard layout class type:
+ if (EvaluateUnaryTypeTrait(Self, UTT_IsScalar, T, KeyLoc))
+ return true;
+ if (EvaluateUnaryTypeTrait(Self, UTT_IsScalar, C.getBaseElementType(T),
+ KeyLoc))
+ return true;
+ if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
+ return RT->hasStandardLayout(C);
+ return false;
+ case UTT_IsUnsigned:
+ return T->isUnsignedIntegerType();
+ case UTT_IsVoid:
+ return T->isVoidType();
+ case UTT_IsVolatile:
+ return T.isVolatileQualified();
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
@@ -2579,11 +2648,12 @@ ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT,
// According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
// all traits except __is_class, __is_enum and __is_union require a the type
// to be complete, an array of unknown bound, or void.
- if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion) {
+ if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion &&
+ UTT != UTT_IsCompleteType) {
QualType E = T;
if (T->isIncompleteArrayType())
E = Context.getAsArrayType(T)->getElementType();
- if (!T->isVoidType() &&
+ if (!T->isVoidType() && ! LangOpts.Borland &&
RequireCompleteType(KWLoc, E,
diag::err_incomplete_type_used_in_type_trait_expr))
return ExprError();
@@ -2651,11 +2721,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
return cast<CXXRecordDecl>(rhsRecord->getDecl())
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
}
-
+ case BTT_IsSame:
+ return Self.Context.hasSameType(LhsT, RhsT);
case BTT_TypeCompatible:
return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(),
RhsT.getUnqualifiedType());
-
+ case BTT_IsConvertible:
case BTT_IsConvertibleTo: {
// C++0x [meta.rel]p4:
// Given the following function prototype:
@@ -2730,6 +2801,8 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
QualType ResultType;
switch (BTT) {
case BTT_IsBaseOf: ResultType = Context.BoolTy; break;
+ case BTT_IsConvertible: ResultType = Context.BoolTy; break;
+ case BTT_IsSame: ResultType = Context.BoolTy; break;
case BTT_TypeCompatible: ResultType = Context.IntTy; break;
case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 05cc5587e1..27777a51c4 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -183,7 +183,7 @@ template <typename T> typename T::U ft6(const T&) { return 0; }
// CHECK: @_Z3ft6I1SENT_1UERKS1_
template int ft6<S>(const S&);
-template<typename> struct __is_scalar {
+template<typename> struct __is_scalar_type {
enum { __value = 1 };
};
@@ -194,11 +194,11 @@ template<typename T> struct __enable_if<true, T> {
};
// PR5063
-template<typename T> typename __enable_if<__is_scalar<T>::__value, void>::__type ft7() { }
+template<typename T> typename __enable_if<__is_scalar_type<T>::__value, void>::__type ft7() { }
-// CHECK: @_Z3ft7IiEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft7<int>();
-// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft7<void*>();
// PR5144
@@ -225,15 +225,15 @@ struct S7 {
S7::S7() {}
// PR5063
-template<typename T> typename __enable_if<(__is_scalar<T>::__value), void>::__type ft8() { }
-// CHECK: @_Z3ft8IiEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+template<typename T> typename __enable_if<(__is_scalar_type<T>::__value), void>::__type ft8() { }
+// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft8<int>();
-// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft8<void*>();
// PR5796
namespace PR5796 {
-template<typename> struct __is_scalar {
+template<typename> struct __is_scalar_type {
enum { __value = 0 };
};
@@ -241,8 +241,8 @@ template<bool, typename> struct __enable_if {};
template<typename T> struct __enable_if<true, T> { typedef T __type; };
template<typename T>
-// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_11__is_scalarIT_EE7__valueEvE6__typeEv
-typename __enable_if<!__is_scalar<T>::__value, void>::__type __fill_a() { };
+// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_16__is_scalar_typeIT_EE7__valueEvE6__typeEv
+typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { };
void f() { __fill_a<int>(); }
}
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index fe5be63961..ef5607b20c 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -244,6 +244,773 @@ void is_polymorphic()
{ int arr[F(__is_polymorphic(IntArNB))]; }
}
+void is_integral()
+{
+ int t01[T(__is_integral(bool))];
+ int t02[T(__is_integral(char))];
+ int t03[T(__is_integral(signed char))];
+ int t04[T(__is_integral(unsigned char))];
+ //int t05[T(__is_integral(char16_t))];
+ //int t06[T(__is_integral(char32_t))];
+ int t07[T(__is_integral(wchar_t))];
+ int t08[T(__is_integral(short))];
+ int t09[T(__is_integral(unsigned short))];
+ int t10[T(__is_integral(int))];
+ int t11[T(__is_integral(unsigned int))];
+ int t12[T(__is_integral(long))];
+ int t13[T(__is_integral(unsigned long))];
+
+ int t21[F(__is_integral(float))];
+ int t22[F(__is_integral(double))];
+ int t23[F(__is_integral(long double))];
+ int t24[F(__is_integral(Union))];
+ int t25[F(__is_integral(UnionAr))];
+ int t26[F(__is_integral(Derives))];
+ int t27[F(__is_integral(ClassType))];
+ int t28[F(__is_integral(Enum))];
+ int t29[F(__is_integral(void))];
+ int t30[F(__is_integral(cvoid))];
+ int t31[F(__is_integral(IntArNB))];
+}
+
+void is_floating_point()
+{
+ int t01[T(__is_floating_point(float))];
+ int t02[T(__is_floating_point(double))];
+ int t03[T(__is_floating_point(long double))];
+
+ int t11[F(__is_floating_point(bool))];
+ int t12[F(__is_floating_point(char))];
+ int t13[F(__is_floating_point(signed char))];
+ int t14[F(__is_floating_point(unsigned char))];
+ //int t15[F(__is_floating_point(char16_t))];
+ //int t16[F(__is_floating_point(char32_t))];
+ int t17[F(__is_floating_point(wchar_t))];
+ int t18[F(__is_floating_point(short))];
+ int t19[F(__is_floating_point(unsigned short))];
+ int t20[F(__is_floating_point(int))];
+ int t21[F(__is_floating_point(unsigned int))];
+ int t22[F(__is_floating_point(long))];
+ int t23[F(__is_floating_point(unsigned long))];
+ int t24[F(__is_floating_point(Union))];
+ int t25[F(__is_floating_point(UnionAr))];
+ int t26[F(__is_floating_point(Derives))];
+ int t27[F(__is_floating_point(ClassType))];
+ int t28[F(__is_floating_point(Enum))];
+ int t29[F(__is_floating_point(void))];
+ int t30[F(__is_floating_point(cvoid))];
+ int t31[F(__is_floating_point(IntArNB))];
+}