Rework the way pointer types are handled by the RTTI builder. We now get the right linkage for indirect pointers to incomplete structs.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91799 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anders Carlsson 2009-12-20 22:30:54 +00:00
Родитель dd4e485a0d
Коммит 8d14515355
3 изменённых файлов: 383 добавлений и 107 удалений

Просмотреть файл

@ -27,29 +27,24 @@ class RTTIBuilder {
std::vector<llvm::Constant *> Info;
// Type info flags.
enum {
/// TI_Const - Type has const qualifier.
TI_Const = 0x1,
/// TI_Volatile - Type has volatile qualifier.
TI_Volatile = 0x2,
/// TI_Restrict - Type has restrict qualifier.
TI_Restrict = 0x4,
/// TI_Incomplete - Type is incomplete.
TI_Incomplete = 0x8,
/// TI_ContainingClassIncomplete - Containing class is incomplete.
/// (in pointer to member).
TI_ContainingClassIncomplete = 0x10
};
/// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
/// descriptor of the given type.
llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
llvm::Constant *BuildTypeInfo(QualType Ty);
/// BuildVtablePointer - Build the vtable pointer for the given type.
void BuildVtablePointer(const Type *Ty);
/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
/// used for pointer types.
void BuildPointerTypeInfo(const PointerType *Ty);
/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
/// struct, used for member pointer types.
void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
public:
RTTIBuilder(CodeGenModule &cgm)
: CGM(cgm), VMContext(cgm.getModule().getContext()),
@ -58,7 +53,7 @@ public:
/// BuildVtableRef - Build a reference to a vtable.
llvm::Constant *BuildVtableRef(const char *Name) {
// Build a descriptor for Name
llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name);
llvm::Constant *GV = CGM.getModule().getNamedGlobal(Name);
if (GV)
GV = llvm::ConstantExpr::getBitCast(GV,
llvm::PointerType::get(Int8PtrTy, 0));
@ -96,7 +91,7 @@ public:
CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name);
llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name);
if (OGV && !OGV->isDeclaration())
return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy);
@ -131,7 +126,7 @@ public:
/// CalculateFlags - Calculate the flags for the __vmi_class_type_info
/// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond
/// shaped class.
int CalculateFlags(const CXXRecordDecl*RD) {
int CalculateFlags(const CXXRecordDecl *RD) {
int flags = 0;
if (SeenBase.count(RD))
flags |= 1;
@ -205,7 +200,7 @@ public:
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
GV = CGM.getModule().getNamedGlobal(Name);
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
@ -293,76 +288,13 @@ public:
return false;
}
llvm::Constant *BuildPointerType(QualType Ty) {
assert(Info.empty() && "Info vector must be empty!");
llvm::Constant *C;
llvm::SmallString<256> OutName;
CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
bool Extern = DecideExtern(Ty);
bool Hidden = DecideHidden(Ty);
const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty);
QualType PointeeTy;
if (PtrMemTy)
PointeeTy = PtrMemTy->getPointeeType();
else
PointeeTy = Ty->getPointeeType();
if (PtrMemTy)
C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE");
else
C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE");
Info.push_back(C);
Info.push_back(BuildName(Ty, Hidden, Extern));
Qualifiers Q = PointeeTy.getQualifiers();
PointeeTy =
CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType();
unsigned Flags = 0;
if (Q.hasConst())
Flags |= TI_Const;
if (Q.hasVolatile())
Flags |= TI_Volatile;
if (Q.hasRestrict())
Flags |= TI_Restrict;
if (Ty->isIncompleteType())
Flags |= TI_Incomplete;
if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType())
Flags |= TI_ContainingClassIncomplete;
Info.push_back(BuildInt(Flags));
Info.push_back(BuildInt(0));
Info.push_back(RTTIBuilder(CGM).BuildType(PointeeTy));
if (PtrMemTy)
Info.push_back(RTTIBuilder(CGM).BuildType(
QualType(PtrMemTy->getClass(), 0)));
// We always generate these as hidden, only the name isn't hidden.
return finish(GV, Name, /*Hidden=*/true, GetLinkageFromExternFlag(Extern));
}
llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) {
llvm::SmallString<256> OutName;
CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
GV = CGM.getModule().getNamedGlobal(Name);
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
@ -397,18 +329,10 @@ public:
return GetAddrOfExternalRTTIDescriptor(Ty);
}
case Type::Pointer: {
QualType PTy = Ty->getPointeeType();
Qualifiers Q = PTy.getQualifiers();
Q.removeConst();
// T* and const T* for all builtin types T are expected in the library.
if (isa<BuiltinType>(PTy) && Q.empty())
return GetAddrOfExternalRTTIDescriptor(Ty);
return BuildPointerType(Ty);
}
case Type::Pointer:
case Type::MemberPointer:
return BuildPointerType(Ty);
return BuildTypeInfo(Ty);
case Type::FunctionProto:
case Type::FunctionNoProto:
return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE");
@ -447,6 +371,25 @@ public:
// linkage.
return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage);
}
// Pointer type info flags.
enum {
/// PTI_Const - Type has const qualifier.
PTI_Const = 0x1,
/// PTI_Volatile - Type has volatile qualifier.
PTI_Volatile = 0x2,
/// PTI_Restrict - Type has restrict qualifier.
PTI_Restrict = 0x4,
/// PTI_Incomplete - Type is incomplete.
PTI_Incomplete = 0x8,
/// PTI_ContainingClassIncomplete - Containing class is incomplete.
/// (in pointer to member).
PTI_ContainingClassIncomplete = 0x10
};
};
}
@ -456,8 +399,8 @@ llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
// Look for an existing global variable.
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
// Look for an existing global.
llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
if (!GV) {
// Create a new global variable.
@ -468,6 +411,316 @@ llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
}
/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
/// info for that type is defined in the standard library.
static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
// Itanium C++ ABI 2.9.2:
// Basic type information (e.g. for "int", "bool", etc.) will be kept in
// the run-time support library. Specifically, the run-time support
// library should contain type_info objects for the types X, X* and
// X const*, for every X in: void, bool, wchar_t, char, unsigned char,
// signed char, short, unsigned short, int, unsigned int, long,
// unsigned long, long long, unsigned long long, float, double, long double,
// char16_t, char32_t, and the IEEE 754r decimal and half-precision
// floating point types.
switch (Ty->getKind()) {
case BuiltinType::Void:
case BuiltinType::Bool:
case BuiltinType::WChar:
case BuiltinType::Char_U:
case BuiltinType::Char_S:
case BuiltinType::UChar:
case BuiltinType::SChar:
case BuiltinType::Short:
case BuiltinType::UShort:
case BuiltinType::Int:
case BuiltinType::UInt:
case BuiltinType::Long:
case BuiltinType::ULong:
case BuiltinType::LongLong:
case BuiltinType::ULongLong:
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
case BuiltinType::Char16:
case BuiltinType::Char32:
case BuiltinType::Int128:
case BuiltinType::UInt128:
return true;
case BuiltinType::Overload:
case BuiltinType::Dependent:
case BuiltinType::UndeducedAuto:
assert(false && "Should not see this type here!");
case BuiltinType::NullPtr:
assert(false && "FIXME: nullptr_t is not handled!");
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
assert(false && "FIXME: Objective-C types are unsupported!");
}
// Silent gcc.
return false;
}
static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
QualType PointeeTy = PointerTy->getPointeeType();
const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
if (!BuiltinTy)
return false;
// Check the qualifiers.
Qualifiers Quals = PointeeTy.getQualifiers();
Quals.removeConst();
if (!Quals.empty())
return false;
return TypeInfoIsInStandardLibrary(BuiltinTy);
}
/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
/// the given type exists somewhere else, and that we should not emit the typ
/// information in this translation unit.
bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
// Type info for builtin types is defined in the standard library.
if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
return TypeInfoIsInStandardLibrary(BuiltinTy);
// Type info for some pointer types to builtin types is defined in the
// standard library.
if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
return TypeInfoIsInStandardLibrary(PointerTy);
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
(void)RecordTy;
assert(false && "FIXME");
}
return false;
}
/// IsIncompleteClassType - Returns whether the given record type is incomplete.
static bool IsIncompleteClassType(const RecordType *RecordTy) {
return !RecordTy->getDecl()->isDefinition();
}
/// IsPointerToIncompleteClassType - Returns whether the given pointer 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);
}
return false;
}
/// 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;
// 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!");
return llvm::GlobalValue::WeakODRLinkage;
}
void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
const char *VtableName;
switch (Ty->getTypeClass()) {
default: assert(0 && "Unhandled type!");
case Type::Pointer:
// abi::__pointer_type_info
VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
break;
case Type::MemberPointer:
// abi::__pointer_to_member_type_info
VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;
}
llvm::Constant *Vtable =
CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy);
const llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1);
Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy);
Info.push_back(Vtable);
}
llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
// Check if we've already emitted an RTTI descriptor for this type.
llvm::SmallString<256> OutName;
CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
if (OldGV && !OldGV->isDeclaration())
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
// Check if there is already an external RTTI descriptor for this type.
if (ShouldUseExternalRTTIDescriptor(Ty))
return GetAddrOfExternalRTTIDescriptor(Ty);
llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
// Add the vtable pointer.
BuildVtablePointer(cast<Type>(Ty));
// And the name.
Info.push_back(BuildName(Ty, DecideHidden(Ty), Linkage));
switch (Ty->getTypeClass()) {
default: assert(false && "Unhandled type class!");
case Type::Builtin:
assert(false && "Builtin type info must be in the standard library!");
break;
case Type::Pointer:
BuildPointerTypeInfo(cast<PointerType>(Ty));
break;
case Type::MemberPointer:
BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
break;
}
llvm::Constant *Init =
llvm::ConstantStruct::get(VMContext, &Info[0], Info.size(),
/*Packed=*/false);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
/*Constant=*/true, Linkage, Init, Name);
// If there's already an old global variable, replace it with the new one.
if (OldGV) {
GV->takeName(OldGV);
llvm::Constant *NewPtr =
llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
OldGV->replaceAllUsesWith(NewPtr);
OldGV->eraseFromParent();
}
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
}
/// DetermineQualifierFlags - Deterine the pointer type info flags from the
/// given qualifier.
static unsigned DetermineQualifierFlags(Qualifiers Quals) {
unsigned Flags = 0;
if (Quals.hasConst())
Flags |= RTTIBuilder::PTI_Const;
if (Quals.hasVolatile())
Flags |= RTTIBuilder::PTI_Volatile;
if (Quals.hasRestrict())
Flags |= RTTIBuilder::PTI_Restrict;
return Flags;
}
/// 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();
// Itanium C++ ABI 2.9.5p7:
// __flags is a flag word describing the cv-qualification and other
// attributes of the type pointed to
unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
// 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))
Flags |= PTI_Incomplete;
const llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
Info.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
// Itanium C++ ABI 2.9.5p7:
// __pointee is a pointer to the std::type_info derivation for the
// unqualified type being pointed to.
Info.push_back(RTTIBuilder(CGM).BuildType(PointeeTy.getUnqualifiedType()));
}
/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
/// struct, used for member pointer types.
void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
QualType PointeeTy = Ty->getPointeeType();
// Itanium C++ ABI 2.9.5p7:
// __flags is a flag word describing the cv-qualification and other
// attributes of the type pointed to.
unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
const RecordType *ClassType = cast<RecordType>(Ty->getClass());
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));
// Itanium C++ ABI 2.9.5p7:
// __pointee is a pointer to the std::type_info derivation for the
// unqualified type being pointed to.
Info.push_back(RTTIBuilder(CGM).BuildType(PointeeTy.getUnqualifiedType()));
// Itanium C++ ABI 2.9.5p9:
// __context is a pointer to an abi::__class_type_info corresponding to the
// class type containing the member pointed to
// (e.g., the "A" in "int A::*").
Info.push_back(RTTIBuilder(CGM).BuildType(QualType(ClassType, 0)));
}
llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
if (!getContext().getLangOptions().RTTI) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);

Просмотреть файл

@ -20,12 +20,20 @@ return static_cast<const T&>(info);
}
struct Incomplete;
#define CHECK(x) if ((x)) return __LINE__;
// CHECK: define i32 @_Z1fv()
int f() {
if (to<__pbase_type_info>(typeid(Incomplete *)).__flags != __pbase_type_info::__incomplete_mask)
return 1;
// 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);
// Member pointers.
CHECK(to<__pbase_type_info>(typeid(int Incomplete::*)).__flags != __pbase_type_info::__incomplete_class_mask);
// Success!
// CHECK: ret i32 0
return 0;
}
@ -38,7 +46,7 @@ int main() {
if (result == 0)
printf("success!\n");
else
printf("test %d failed!\n", result);
printf("test on line %d failed!\n", result);
return result;
}

Просмотреть файл

@ -1,10 +1,14 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
#include <typeinfo>
// CHECK: _ZTS1B = constant
// CHECK: _ZTS1A = weak_odr constant
// CHECK: _ZTI1A = weak_odr constant
// CHECK: _ZTI1B = constant
// CHECK: _ZTSP1C = internal constant
// CHECK: _ZTIP1C = internal constant
// CHECK: _ZTSPP1C = internal constant
// CHECK: _ZTIPP1C = internal constant
// A has no key function, so its RTTI data should be weak_odr.
struct A { };
@ -14,3 +18,14 @@ struct B : A {
virtual void f();
};
void B::f() { }
// C is an incomplete class type, so any direct or indirect pointer types should have
// internal linkage, as should the type info for C itself (FIXME).
struct C;
void f() {
(void)typeid(C*);
(void)typeid(C**);
}