Implement RTTI generation for Objective C types.  Fixes PR7864.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110900 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 7dce9a0..6917141 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -45,7 +45,11 @@
   
   /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
   /// for pointer types.
-  void BuildPointerTypeInfo(const PointerType *Ty);
+  void BuildPointerTypeInfo(QualType PointeeTy);
+
+  /// BuildObjCObjectTypeInfo - Build the appropriate kind of
+  /// type_info for an object type.
+  void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
   
   /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info 
   /// struct, used for member pointer types.
@@ -390,6 +394,16 @@
 }
 
 void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
+  // abi::__class_type_info.
+  static const char * const ClassTypeInfo =
+    "_ZTVN10__cxxabiv117__class_type_infoE";
+  // abi::__si_class_type_info.
+  static const char * const SIClassTypeInfo =
+    "_ZTVN10__cxxabiv120__si_class_type_infoE";
+  // abi::__vmi_class_type_info.
+  static const char * const VMIClassTypeInfo =
+    "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+
   const char *VTableName = 0;
 
   switch (Ty->getTypeClass()) {
@@ -433,32 +447,44 @@
     // abi::__enum_type_info.
     VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
     break;
-      
+
   case Type::Record: {
     const CXXRecordDecl *RD = 
       cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
     
     if (!RD->hasDefinition() || !RD->getNumBases()) {
-      // abi::__class_type_info.
-      VTableName = "_ZTVN10__cxxabiv117__class_type_infoE";
+      VTableName = ClassTypeInfo;
     } else if (CanUseSingleInheritance(RD)) {
-      // abi::__si_class_type_info.
-      VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
+      VTableName = SIClassTypeInfo;
     } else {
-      // abi::__vmi_class_type_info.
-      VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+      VTableName = VMIClassTypeInfo;
     }
     
     break;
   }
 
   case Type::ObjCObject:
+    // Ignore protocol qualifiers.
+    Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
+
+    // Handle id and Class.
+    if (isa<BuiltinType>(Ty)) {
+      VTableName = ClassTypeInfo;
+      break;
+    }
+
+    assert(isa<ObjCInterfaceType>(Ty));
+    // Fall through.
+
   case Type::ObjCInterface:
-  case Type::ObjCObjectPointer:
-    assert(false && "FIXME: Needs to be written!");
-    VTableName = "_ZTVN10__cxxabiv117__class_type_infoE";
+    if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
+      VTableName = SIClassTypeInfo;
+    } else {
+      VTableName = ClassTypeInfo;
+    }
     break;
 
+  case Type::ObjCObjectPointer:
   case Type::Pointer:
     // abi::__pointer_type_info.
     VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
@@ -559,11 +585,20 @@
 
     break;
   }
+
+  case Type::ObjCObject:
+  case Type::ObjCInterface:
+    BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
+    break;
+
+  case Type::ObjCObjectPointer:
+    BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+    break; 
       
   case Type::Pointer:
-    BuildPointerTypeInfo(cast<PointerType>(Ty));
+    BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
     break;
-  
+
   case Type::MemberPointer:
     BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
     break;
@@ -612,6 +647,30 @@
   return Flags;
 }
 
+/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
+/// for the given Objective-C object type.
+void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
+  // Drop qualifiers.
+  const Type *T = OT->getBaseType().getTypePtr();
+  assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
+
+  // The builtin types are abi::__class_type_infos and don't require
+  // extra fields.
+  if (isa<BuiltinType>(T)) return;
+
+  ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
+  ObjCInterfaceDecl *Super = Class->getSuperClass();
+
+  // Root classes are also __class_type_info.
+  if (!Super) return;
+
+  QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
+
+  // Everything else is single inheritance.
+  llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy);
+  Fields.push_back(BaseTypeInfo);
+}
+
 /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
 /// inheritance, according to the Itanium C++ ABI, 2.95p6b.
 void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
@@ -767,9 +826,7 @@
 
 /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
 /// used for pointer types.
-void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
-  QualType PointeeTy = Ty->getPointeeType();
-  
+void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {  
   Qualifiers Quals;
   QualType UnqualifiedPointeeTy = 
     CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
diff --git a/test/CodeGenObjCXX/rtti.mm b/test/CodeGenObjCXX/rtti.mm
new file mode 100644
index 0000000..d24eaa6
--- /dev/null
+++ b/test/CodeGenObjCXX/rtti.mm
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// PR7864.  This all follows GCC's lead.
+
+namespace std { class type_info; }
+
+// CHECK: @_ZTI1A = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv117__class_type_infoE{{.*}}@_ZTS1A
+@interface A
+@end
+
+// CHECK: @_ZTI1B = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv120__si_class_type_infoE{{.*}}@_ZTS1B{{.*}}@_ZTI1A
+@interface B : A
+@end
+
+// CHECK: @_ZTIP1B = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv119__pointer_type_infoE{{.*}}@_ZTSP1B{{.*}}), i32 0, {{.*}}@_ZTI1B
+// CHECK: @_ZTI11objc_object = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv117__class_type_infoE{{.*}}@_ZTS11objc_object
+// CHECK: @_ZTIP11objc_object = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv119__pointer_type_infoE{{.*}}@_ZTSP11objc_object{{.*}}@_ZTI11objc_object
+// CHECK: @_ZTI10objc_class = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv117__class_type_infoE{{.*}}@_ZTS10objc_class
+// CHECK: @_ZTIP10objc_class = weak_odr hidden constant {{.*}}@_ZTVN10__cxxabiv119__pointer_type_infoE{{.*}}@_ZTSP10objc_class{{.*}}@_ZTI10objc_class
+
+@protocol P;
+
+int main() {
+  // CHECK: store {{.*}} @_ZTIP1B
+  // CHECK: store {{.*}} @_ZTI1B
+  const std::type_info &t1 = typeid(B*);
+  const std::type_info &t2 = typeid(B);
+
+  // CHECK: store {{.*}} @_ZTIP11objc_object
+  // CHECK: store {{.*}} @_ZTI11objc_object
+  id i = 0;
+  const std::type_info &t3 = typeid(i);
+  const std::type_info &t4 = typeid(*i);
+
+  // CHECK: store {{.*}} @_ZTIP10objc_class
+  // CHECK: store {{.*}} @_ZTI10objc_class
+  Class c = 0;
+  const std::type_info &t5 = typeid(c);
+  const std::type_info &t6 = typeid(*c);
+
+  // CHECK: store {{.*}} @_ZTIP11objc_object
+  // CHECK: store {{.*}} @_ZTI11objc_object
+  id<P> i2 = 0;
+  const std::type_info &t7 = typeid(i2);
+  const std::type_info &t8 = typeid(*i2);
+
+  // CHECK: store {{.*}} @_ZTIP10objc_class
+  // CHECK: store {{.*}} @_ZTI10objc_class
+  Class<P> c2 = 0;
+  const std::type_info &t9 = typeid(c2);
+  const std::type_info &t10 = typeid(*c2);
+}