forked from OSchip/llvm-project
Correcly handle pointers to member pointer types where the class or the pointee is incomplete.
llvm-svn: 91804
This commit is contained in:
parent
518e370719
commit
18e6ee1b20
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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::*);
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue