From 18e6ee1b20727e86f396f39e7bb3e83f58a90c1c Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 20 Dec 2009 23:37:55 +0000 Subject: [PATCH] Correcly handle pointers to member pointer types where the class or the pointee is incomplete. llvm-svn: 91804 --- clang/lib/CodeGen/CGRTTI.cpp | 90 ++++++++++++++------------ clang/test/CodeGenCXX/rtti-layout.cpp | 14 ++-- clang/test/CodeGenCXX/rtti-linkage.cpp | 19 ++++++ 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index 844009affbc1..416bb1694c52 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -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(PointeeTy))) - PointeeTy = PointerTy->getPointeeType(); - - if (const RecordType *RecordTy = dyn_cast(PointeeTy)) { - // Check if the record type is incomplete. - return IsIncompleteClassType(RecordTy); +static bool ContainsIncompleteClassType(QualType Ty) { + if (const RecordType *RecordTy = dyn_cast(Ty)) { + if (IsIncompleteClassType(RecordTy)) + return true; + } + + if (const PointerType *PointerTy = dyn_cast(Ty)) + return ContainsIncompleteClassType(PointerTy->getPointeeType()); + + if (const MemberPointerType *MemberPointerTy = + dyn_cast(Ty)) { + // Check if the class type is incomplete. + const RecordType *ClassType = cast(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(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(Ty)) { - // If the class type is incomplete, then the type info constants should - // have internal linkage. - const RecordType *ClassType = cast(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(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(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)); diff --git a/clang/test/CodeGenCXX/rtti-layout.cpp b/clang/test/CodeGenCXX/rtti-layout.cpp index 3e97592ada1a..c8326bbd8937 100644 --- a/clang/test/CodeGenCXX/rtti-layout.cpp +++ b/clang/test/CodeGenCXX/rtti-layout.cpp @@ -20,17 +20,21 @@ return static_cast(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 diff --git a/clang/test/CodeGenCXX/rtti-linkage.cpp b/clang/test/CodeGenCXX/rtti-linkage.cpp index 22e859d69c96..5b4a8e42dd6f 100644 --- a/clang/test/CodeGenCXX/rtti-linkage.cpp +++ b/clang/test/CodeGenCXX/rtti-linkage.cpp @@ -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::*); }