]> granicus.if.org Git - clang/commitdiff
Correcly handle pointers to member pointer types where the class or the pointee is...
authorAnders Carlsson <andersca@mac.com>
Sun, 20 Dec 2009 23:37:55 +0000 (23:37 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 20 Dec 2009 23:37:55 +0000 (23:37 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91804 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGRTTI.cpp
test/CodeGenCXX/rtti-layout.cpp
test/CodeGenCXX/rtti-linkage.cpp

index 844009affbc1180277dc5dea42769950b57ce551..416bb1694c52d5d6271b78d38598733a27ecd29e 100644 (file)
@@ -508,16 +508,34 @@ static bool IsIncompleteClassType(const RecordType *RecordTy) {
   return !RecordTy->getDecl()->isDefinition();
 }  
 
-/// IsPointerToIncompleteClassType - Returns whether the given pointer type
+/// ContainsIncompleteClassType - Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+///   * The given type is an incomplete class type.
+///   * The given type is a pointer type whose pointee type contains an 
+///     incomplete class type.
+///   * The given type is a member pointer type whose class is an incomplete
+///     class type.
+///   * The given type is a member pointer type whoise pointee type contains an
+///     incomplete class type.
 /// is an indirect or direct pointer to an incomplete class type.
-static bool IsPointerToIncompleteClassType(const PointerType *PointerTy) {
-  QualType PointeeTy = PointerTy->getPointeeType();
-  while ((PointerTy = dyn_cast<PointerType>(PointeeTy)))
-    PointeeTy = PointerTy->getPointeeType();
-
-  if (const RecordType *RecordTy = dyn_cast<RecordType>(PointeeTy)) {
-    // Check if the record type is incomplete.
-    return IsIncompleteClassType(RecordTy);
+static bool ContainsIncompleteClassType(QualType Ty) {
+  if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+    if (IsIncompleteClassType(RecordTy))
+      return true;
+  }
+  
+  if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+    return ContainsIncompleteClassType(PointerTy->getPointeeType());
+  
+  if (const MemberPointerType *MemberPointerTy = 
+      dyn_cast<MemberPointerType>(Ty)) {
+    // Check if the class type is incomplete.
+    const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
+    if (IsIncompleteClassType(ClassType))
+      return true;
+    
+    return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
   }
   
   return false;
@@ -526,34 +544,19 @@ static bool IsPointerToIncompleteClassType(const PointerType *PointerTy) {
 /// getTypeInfoLinkage - Return the linkage that the type info and type info
 /// name constants should have for the given type.
 static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
-  if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) {
-    // Itanium C++ ABI 2.9.5p7:
-    //   In addition, it and all of the intermediate abi::__pointer_type_info 
-    //   structs in the chain down to the abi::__class_type_info for the
-    //   incomplete class type must be prevented from resolving to the 
-    //   corresponding type_info structs for the complete class type, possibly
-    //   by making them local static objects. Finally, a dummy class RTTI is
-    //   generated for the incomplete type that will not resolve to the final 
-    //   complete class RTTI (because the latter need not exist), possibly by 
-    //   making it a local static object.
-    if (IsPointerToIncompleteClassType(PointerTy))
-      return llvm::GlobalValue::InternalLinkage;
+  // Itanium C++ ABI 2.9.5p7:
+  //   In addition, it and all of the intermediate abi::__pointer_type_info 
+  //   structs in the chain down to the abi::__class_type_info for the
+  //   incomplete class type must be prevented from resolving to the 
+  //   corresponding type_info structs for the complete class type, possibly
+  //   by making them local static objects. Finally, a dummy class RTTI is
+  //   generated for the incomplete type that will not resolve to the final 
+  //   complete class RTTI (because the latter need not exist), possibly by 
+  //   making it a local static object.
+  if (ContainsIncompleteClassType(Ty))
+    return llvm::GlobalValue::InternalLinkage;
    
-    // FIXME: Check linkage and anonymous namespace.
-    return llvm::GlobalValue::WeakODRLinkage;
-  } else if (const MemberPointerType *MemberPointerTy = 
-              dyn_cast<MemberPointerType>(Ty)) {
-    // If the class type is incomplete, then the type info constants should 
-    // have internal linkage.
-    const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
-    if (!ClassType->getDecl()->isDefinition())
-      return llvm::GlobalValue::InternalLinkage;
-    
-    // FIXME: Check linkage and anonymous namespace.
-    return llvm::GlobalValue::WeakODRLinkage;
-  }
-
-  assert(false && "FIXME!");
+  // FIXME: Check linkage and anonymous namespace.
   return llvm::GlobalValue::WeakODRLinkage;
 }
 
@@ -664,8 +667,7 @@ static unsigned DetermineQualifierFlags(Qualifiers Quals) {
 /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
 /// used for pointer types.
 void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
-  const PointerType *PointerTy = cast<PointerType>(Ty);
-  QualType PointeeTy = PointerTy->getPointeeType();
+  QualType PointeeTy = Ty->getPointeeType();
   
   // Itanium C++ ABI 2.9.5p7:
   //   __flags is a flag word describing the cv-qualification and other 
@@ -675,7 +677,7 @@ void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
   // Itanium C++ ABI 2.9.5p7:
   //   When the abi::__pbase_type_info is for a direct or indirect pointer to an
   //   incomplete class type, the incomplete target type flag is set. 
-  if (IsPointerToIncompleteClassType(PointerTy))
+  if (ContainsIncompleteClassType(PointeeTy))
     Flags |= PTI_Incomplete;
 
   const llvm::Type *UnsignedIntLTy = 
@@ -699,12 +701,16 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
   unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
 
   const RecordType *ClassType = cast<RecordType>(Ty->getClass());
-  
+
+  // Itanium C++ ABI 2.9.5p7:
+  //   When the abi::__pbase_type_info is for a direct or indirect pointer to an
+  //   incomplete class type, the incomplete target type flag is set. 
+  if (ContainsIncompleteClassType(PointeeTy))
+    Flags |= PTI_Incomplete;
+
   if (IsIncompleteClassType(ClassType))
     Flags |= PTI_ContainingClassIncomplete;
   
-  // FIXME: Handle PTI_Incomplete.
-  
   const llvm::Type *UnsignedIntLTy = 
     CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
   Info.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
index 3e97592ada1ad851cb7b24b5132132d8100a2e55..c8326bbd89371e67cc6138c8ad90cb00728afbbb 100644 (file)
@@ -20,17 +20,21 @@ return static_cast<const T&>(info);
 }
 struct Incomplete;
 
-#define CHECK(x) if ((x)) return __LINE__;
+struct A { };
+
+#define CHECK(x) if (!(x)) return __LINE__;
 
 // CHECK: define i32 @_Z1fv()
 int f() {
   // Pointers to incomplete classes.
-  CHECK(to<__pbase_type_info>(typeid(Incomplete *)).__flags != __pbase_type_info::__incomplete_mask);
-  CHECK(to<__pbase_type_info>(typeid(Incomplete **)).__flags != __pbase_type_info::__incomplete_mask);
-  CHECK(to<__pbase_type_info>(typeid(Incomplete ***)).__flags != __pbase_type_info::__incomplete_mask);
+  CHECK(to<__pbase_type_info>(typeid(Incomplete *)).__flags == __pbase_type_info::__incomplete_mask);
+  CHECK(to<__pbase_type_info>(typeid(Incomplete **)).__flags == __pbase_type_info::__incomplete_mask);
+  CHECK(to<__pbase_type_info>(typeid(Incomplete ***)).__flags == __pbase_type_info::__incomplete_mask);
 
   // Member pointers.
-  CHECK(to<__pbase_type_info>(typeid(int Incomplete::*)).__flags != __pbase_type_info::__incomplete_class_mask);
+  CHECK(to<__pbase_type_info>(typeid(int Incomplete::*)).__flags == __pbase_type_info::__incomplete_class_mask);
+  CHECK(to<__pbase_type_info>(typeid(Incomplete Incomplete::*)).__flags == (__pbase_type_info::__incomplete_class_mask | __pbase_type_info::__incomplete_mask));
+  CHECK(to<__pbase_type_info>(typeid(Incomplete A::*)).__flags == (__pbase_type_info::__incomplete_mask));
 
   // Success!
   // CHECK: ret i32 0
index 22e859d69c9661ae2bda79a77a5900a9a0d06948..5b4a8e42dd6faeadbf4de1ce7b4e5e4a2146159a 100644 (file)
@@ -9,6 +9,19 @@
 // CHECK: _ZTIP1C = internal constant
 // CHECK: _ZTSPP1C = internal constant
 // CHECK: _ZTIPP1C = internal constant
+// CHECK: _ZTSM1Ci = internal constant
+// CHECK: _ZTIM1Ci = internal constant
+// CHECK: _ZTSPM1Ci = internal constant
+// CHECK: _ZTIPM1Ci = internal constant
+// CHECK: _ZTSM1CS_ = internal constant
+// CHECK: _ZTIM1CS_ = internal constant
+// CHECK: _ZTSM1CPS_ = internal constant
+// CHECK: _ZTIM1CPS_ = internal constant
+// CHECK: _ZTSM1A1C = internal constant
+// CHECK: _ZTIM1A1C = internal constant
+// CHECK: _ZTSM1AP1C = internal constant
+// CHECK: _ZTIM1AP1C = internal constant
+
 // A has no key function, so its RTTI data should be weak_odr.
 struct A { };
 
@@ -26,6 +39,12 @@ struct C;
 void f() {
   (void)typeid(C*);
   (void)typeid(C**);
+  (void)typeid(int C::*);
+  (void)typeid(int C::**);
+  (void)typeid(C C::*);
+  (void)typeid(C *C::*);
+  (void)typeid(C A::*);
+  (void)typeid(C* A::*);
   
 }