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());
 }
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f593028..c41798e 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -731,22 +731,19 @@
   // 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 c990c52..1c4a942 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -519,6 +519,34 @@
 ///                   '::'[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 @@
 ///       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 @@
   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 @@
 
   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 7bf76a9..aade050 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1912,25 +1912,50 @@
 
 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 @@
   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 f8ad763..7086176 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2379,6 +2379,7 @@
     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 @@
           && 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 @@
   // 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 @@
     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 @@
   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;
   }