Correcly handle pointers to member pointer types where the class or the pointee is incomplete.

llvm-svn: 91804
This commit is contained in:
Anders Carlsson 2009-12-20 23:37:55 +00:00
parent 518e370719
commit 18e6ee1b20
3 changed files with 76 additions and 47 deletions

View 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));

View 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

View 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::*);
}