forked from OSchip/llvm-project
Fix a bunch of bugs with VMI RTTI building, and add a whole bunch of tests.
llvm-svn: 92319
This commit is contained in:
parent
da3ddfce43
commit
a442499072
|
@ -21,10 +21,8 @@ namespace {
|
||||||
class RTTIBuilder {
|
class RTTIBuilder {
|
||||||
CodeGenModule &CGM; // Per-module state.
|
CodeGenModule &CGM; // Per-module state.
|
||||||
llvm::LLVMContext &VMContext;
|
llvm::LLVMContext &VMContext;
|
||||||
const llvm::Type *Int8PtrTy;
|
|
||||||
llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase;
|
|
||||||
llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase;
|
|
||||||
|
|
||||||
|
const llvm::Type *Int8PtrTy;
|
||||||
std::vector<llvm::Constant *> Info;
|
std::vector<llvm::Constant *> Info;
|
||||||
|
|
||||||
/// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
|
/// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
|
||||||
|
@ -38,9 +36,14 @@ class RTTIBuilder {
|
||||||
void BuildVtablePointer(const Type *Ty);
|
void BuildVtablePointer(const Type *Ty);
|
||||||
|
|
||||||
/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
|
/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
|
||||||
/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
|
/// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
|
||||||
void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
|
void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
|
||||||
|
|
||||||
|
/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
|
||||||
|
/// classes with bases that do not satisfy the abi::__si_class_type_info
|
||||||
|
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
|
||||||
|
void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
|
||||||
|
|
||||||
/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
|
/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
|
||||||
/// for pointer types.
|
/// for pointer types.
|
||||||
void BuildPointerTypeInfo(const PointerType *Ty);
|
void BuildPointerTypeInfo(const PointerType *Ty);
|
||||||
|
@ -54,25 +57,6 @@ public:
|
||||||
: CGM(cgm), VMContext(cgm.getModule().getContext()),
|
: CGM(cgm), VMContext(cgm.getModule().getContext()),
|
||||||
Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
|
Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
|
||||||
|
|
||||||
/// BuildVtableRef - Build a reference to a vtable.
|
|
||||||
llvm::Constant *BuildVtableRef(const char *Name) {
|
|
||||||
// Build a descriptor for Name
|
|
||||||
llvm::Constant *GV = CGM.getModule().getNamedGlobal(Name);
|
|
||||||
if (GV)
|
|
||||||
GV = llvm::ConstantExpr::getBitCast(GV,
|
|
||||||
llvm::PointerType::get(Int8PtrTy, 0));
|
|
||||||
else {
|
|
||||||
llvm::GlobalVariable::LinkageTypes linktype;
|
|
||||||
linktype = llvm::GlobalValue::ExternalLinkage;
|
|
||||||
GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy,
|
|
||||||
true, linktype, 0, Name);
|
|
||||||
}
|
|
||||||
llvm::Constant *C;
|
|
||||||
C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2);
|
|
||||||
C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1);
|
|
||||||
return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: This should be removed, and clients should pass in the linkage
|
// FIXME: This should be removed, and clients should pass in the linkage
|
||||||
// directly instead.
|
// directly instead.
|
||||||
static inline llvm::GlobalVariable::LinkageTypes
|
static inline llvm::GlobalVariable::LinkageTypes
|
||||||
|
@ -127,145 +111,6 @@ public:
|
||||||
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c);
|
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 flags = 0;
|
|
||||||
if (SeenBase.count(RD))
|
|
||||||
flags |= 1;
|
|
||||||
else
|
|
||||||
SeenBase.insert(RD);
|
|
||||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
|
||||||
e = RD->bases_end(); i != e; ++i) {
|
|
||||||
const CXXRecordDecl *Base =
|
|
||||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
|
||||||
if (i->isVirtual()) {
|
|
||||||
if (SeenVBase.count(Base))
|
|
||||||
flags |= 2;
|
|
||||||
else
|
|
||||||
SeenVBase.insert(Base);
|
|
||||||
}
|
|
||||||
flags |= CalculateFlags(Base);
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimpleInheritance(const CXXRecordDecl *RD) {
|
|
||||||
if (RD->getNumBases() != 1)
|
|
||||||
return false;
|
|
||||||
CXXRecordDecl::base_class_const_iterator i = RD->bases_begin();
|
|
||||||
if (i->isVirtual())
|
|
||||||
return false;
|
|
||||||
if (i->getAccessSpecifier() != AS_public)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
|
||||||
const CXXRecordDecl *Base =
|
|
||||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
|
||||||
if (Layout.getBaseClassOffset(Base) != 0)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Constant *finish(llvm::GlobalVariable *GV,
|
|
||||||
llvm::StringRef Name, bool Hidden,
|
|
||||||
llvm::GlobalVariable::LinkageTypes Linkage) {
|
|
||||||
llvm::Constant *C =
|
|
||||||
llvm::ConstantStruct::get(VMContext, &Info[0], Info.size(),
|
|
||||||
/*Packed=*/false);
|
|
||||||
|
|
||||||
llvm::GlobalVariable *OGV = GV;
|
|
||||||
GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage,
|
|
||||||
C, Name);
|
|
||||||
if (OGV) {
|
|
||||||
GV->takeName(OGV);
|
|
||||||
llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
|
|
||||||
OGV->getType());
|
|
||||||
OGV->replaceAllUsesWith(NewPtr);
|
|
||||||
OGV->eraseFromParent();
|
|
||||||
}
|
|
||||||
if (Hidden)
|
|
||||||
GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
|
|
||||||
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
llvm::Constant *
|
|
||||||
Buildclass_type_info(const CXXRecordDecl *RD,
|
|
||||||
llvm::GlobalVariable::LinkageTypes Linkage) {
|
|
||||||
assert(Info.empty() && "Info vector must be empty!");
|
|
||||||
|
|
||||||
llvm::Constant *C;
|
|
||||||
|
|
||||||
llvm::SmallString<256> OutName;
|
|
||||||
CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD),
|
|
||||||
OutName);
|
|
||||||
llvm::StringRef Name = OutName.str();
|
|
||||||
|
|
||||||
llvm::GlobalVariable *GV;
|
|
||||||
GV = CGM.getModule().getNamedGlobal(Name);
|
|
||||||
if (GV && !GV->isDeclaration())
|
|
||||||
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
|
|
||||||
|
|
||||||
// If we're in an anonymous namespace, then we always want internal linkage.
|
|
||||||
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
|
|
||||||
Linkage = llvm::GlobalVariable::InternalLinkage;
|
|
||||||
|
|
||||||
bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
|
|
||||||
|
|
||||||
bool simple = false;
|
|
||||||
if (RD->getNumBases() == 0)
|
|
||||||
C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE");
|
|
||||||
else if (SimpleInheritance(RD)) {
|
|
||||||
simple = true;
|
|
||||||
C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE");
|
|
||||||
} else
|
|
||||||
C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE");
|
|
||||||
Info.push_back(C);
|
|
||||||
Info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden,
|
|
||||||
Linkage));
|
|
||||||
|
|
||||||
// If we have no bases, there are no more fields.
|
|
||||||
if (RD->getNumBases()) {
|
|
||||||
if (!simple) {
|
|
||||||
Info.push_back(BuildFlags(CalculateFlags(RD)));
|
|
||||||
Info.push_back(BuildBaseCount(RD->getNumBases()));
|
|
||||||
}
|
|
||||||
|
|
||||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
|
||||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
|
||||||
e = RD->bases_end(); i != e; ++i) {
|
|
||||||
QualType BaseType = i->getType();
|
|
||||||
const CXXRecordDecl *Base =
|
|
||||||
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
|
||||||
Info.push_back(CGM.GetAddrOfRTTIDescriptor(BaseType));
|
|
||||||
if (simple)
|
|
||||||
break;
|
|
||||||
int64_t offset;
|
|
||||||
if (!i->isVirtual())
|
|
||||||
offset = Layout.getBaseClassOffset(Base)/8;
|
|
||||||
else
|
|
||||||
offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
|
|
||||||
offset <<= 8;
|
|
||||||
// Now set the flags.
|
|
||||||
offset += i->isVirtual() ? 1 : 0;;
|
|
||||||
offset += i->getAccessSpecifier() == AS_public ? 2 : 0;
|
|
||||||
const llvm::Type *LongTy =
|
|
||||||
CGM.getTypes().ConvertType(CGM.getContext().LongTy);
|
|
||||||
C = llvm::ConstantInt::get(LongTy, offset);
|
|
||||||
Info.push_back(C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return finish(GV, Name, Hidden, Linkage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// - BuildFlags - Build a __flags value for __pbase_type_info.
|
|
||||||
llvm::Constant *BuildInt(unsigned n) {
|
|
||||||
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: unify with DecideExtern
|
// FIXME: unify with DecideExtern
|
||||||
bool DecideHidden(QualType Ty) {
|
bool DecideHidden(QualType Ty) {
|
||||||
// For this type, see if all components are never hidden.
|
// For this type, see if all components are never hidden.
|
||||||
|
@ -309,16 +154,7 @@ public:
|
||||||
return GetAddrOfExternalRTTIDescriptor(Ty);
|
return GetAddrOfExternalRTTIDescriptor(Ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::Record: {
|
case Type::Record:
|
||||||
const RecordType *RT = cast<RecordType>(&Type);
|
|
||||||
|
|
||||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
|
||||||
if (RD->getNumBases() != 0 && !SimpleInheritance(RD))
|
|
||||||
return BuildClassTypeInfo(RD);
|
|
||||||
|
|
||||||
// Fall through.
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type::Pointer:
|
case Type::Pointer:
|
||||||
case Type::MemberPointer:
|
case Type::MemberPointer:
|
||||||
case Type::FunctionProto:
|
case Type::FunctionProto:
|
||||||
|
@ -333,31 +169,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BuildClassTypeInfo - Builds the class type info (or a reference to it)
|
|
||||||
/// for the given record decl.
|
|
||||||
llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) {
|
|
||||||
const CXXMethodDecl *KeyFunction = 0;
|
|
||||||
|
|
||||||
if (RD->isDynamicClass())
|
|
||||||
KeyFunction = CGM.getContext().getKeyFunction(RD);
|
|
||||||
|
|
||||||
if (KeyFunction) {
|
|
||||||
// If the key function is defined in this translation unit, then the RTTI
|
|
||||||
// related constants should also be emitted here, with external linkage.
|
|
||||||
if (KeyFunction->getBody())
|
|
||||||
return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage);
|
|
||||||
|
|
||||||
// Otherwise, we just want a reference to the type info.
|
|
||||||
QualType Ty = CGM.getContext().getTagDeclType(RD);
|
|
||||||
return GetAddrOfExternalRTTIDescriptor(Ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no key function (or if the record doesn't have any virtual
|
|
||||||
// member functions or virtual bases), emit the type info with weak_odr
|
|
||||||
// linkage.
|
|
||||||
return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer type info flags.
|
// Pointer type info flags.
|
||||||
enum {
|
enum {
|
||||||
/// PTI_Const - Type has const qualifier.
|
/// PTI_Const - Type has const qualifier.
|
||||||
|
@ -376,6 +187,24 @@ public:
|
||||||
/// (in pointer to member).
|
/// (in pointer to member).
|
||||||
PTI_ContainingClassIncomplete = 0x10
|
PTI_ContainingClassIncomplete = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// VMI type info flags.
|
||||||
|
enum {
|
||||||
|
/// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
|
||||||
|
VMI_NonDiamondRepeat = 0x1,
|
||||||
|
|
||||||
|
/// VMI_DiamondShaped - Class is diamond shaped.
|
||||||
|
VMI_DiamondShaped = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class type info flags.
|
||||||
|
enum {
|
||||||
|
/// BCTI_Virtual - Base class is virtual.
|
||||||
|
BCTI_Virtual = 0x1,
|
||||||
|
|
||||||
|
/// BCTI_Public - Base class is public.
|
||||||
|
BCTI_Public = 0x2
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,50 +508,52 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
|
||||||
// GCC treats vector types as fundamental types.
|
// GCC treats vector types as fundamental types.
|
||||||
case Type::Vector:
|
case Type::Vector:
|
||||||
case Type::ExtVector:
|
case Type::ExtVector:
|
||||||
// abi::__fundamental_type_info
|
// abi::__fundamental_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::ConstantArray:
|
case Type::ConstantArray:
|
||||||
case Type::IncompleteArray:
|
case Type::IncompleteArray:
|
||||||
// abi::__array_type_info
|
// abi::__array_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::FunctionNoProto:
|
case Type::FunctionNoProto:
|
||||||
case Type::FunctionProto:
|
case Type::FunctionProto:
|
||||||
// abi::__function_type_info
|
// abi::__function_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::Enum:
|
case Type::Enum:
|
||||||
// abi::__enum_type_info
|
// abi::__enum_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::Record: {
|
case Type::Record: {
|
||||||
const CXXRecordDecl *RD =
|
const CXXRecordDecl *RD =
|
||||||
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
|
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
|
||||||
|
|
||||||
if (!RD->getNumBases()) {
|
if (!RD->getNumBases()) {
|
||||||
// abi::__class_type_info
|
// abi::__class_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
|
||||||
} else if (CanUseSingleInheritance(RD)) {
|
} else if (CanUseSingleInheritance(RD)) {
|
||||||
// abi::__si_class_type_info;
|
// abi::__si_class_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
|
||||||
} else {
|
} else {
|
||||||
assert(false && "Should not get here!");
|
// abi::__vmi_class_type_info.
|
||||||
|
VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::Pointer:
|
case Type::Pointer:
|
||||||
// abi::__pointer_type_info
|
// abi::__pointer_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type::MemberPointer:
|
case Type::MemberPointer:
|
||||||
// abi::__pointer_to_member_type_info
|
// abi::__pointer_to_member_type_info.
|
||||||
VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
|
VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -804,11 +635,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanUseSingleInheritance(RD)) {
|
if (CanUseSingleInheritance(RD))
|
||||||
BuildSIClassTypeInfo(RD);
|
BuildSIClassTypeInfo(RD);
|
||||||
|
else
|
||||||
|
BuildVMIClassTypeInfo(RD);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case Type::Pointer:
|
case Type::Pointer:
|
||||||
BuildPointerTypeInfo(cast<PointerType>(Ty));
|
BuildPointerTypeInfo(cast<PointerType>(Ty));
|
||||||
|
@ -839,9 +672,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
|
||||||
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
|
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DetermineQualifierFlags - Deterine the pointer type info flags from the
|
/// ComputeQualifierFlags - Compute the pointer type info flags from the
|
||||||
/// given qualifier.
|
/// given qualifier.
|
||||||
static unsigned DetermineQualifierFlags(Qualifiers Quals) {
|
static unsigned ComputeQualifierFlags(Qualifiers Quals) {
|
||||||
unsigned Flags = 0;
|
unsigned Flags = 0;
|
||||||
|
|
||||||
if (Quals.hasConst())
|
if (Quals.hasConst())
|
||||||
|
@ -863,6 +696,148 @@ void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
|
||||||
Info.push_back(RTTIBuilder(CGM).BuildType(RD->bases_begin()->getType()));
|
Info.push_back(RTTIBuilder(CGM).BuildType(RD->bases_begin()->getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SeenBases - Contains virtual and non-virtual bases seen when traversing
|
||||||
|
/// a class hierarchy.
|
||||||
|
struct SeenBases {
|
||||||
|
llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
|
||||||
|
llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
|
||||||
|
/// abi::__vmi_class_type_info.
|
||||||
|
///
|
||||||
|
static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
|
||||||
|
SeenBases &Bases) {
|
||||||
|
|
||||||
|
unsigned Flags = 0;
|
||||||
|
|
||||||
|
const CXXRecordDecl *BaseDecl =
|
||||||
|
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||||
|
|
||||||
|
if (Base->isVirtual()) {
|
||||||
|
if (Bases.VirtualBases.count(BaseDecl)) {
|
||||||
|
// If this virtual base has been seen before, then the class is diamond
|
||||||
|
// shaped.
|
||||||
|
Flags |= RTTIBuilder::VMI_DiamondShaped;
|
||||||
|
} else {
|
||||||
|
if (Bases.NonVirtualBases.count(BaseDecl))
|
||||||
|
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
|
||||||
|
|
||||||
|
// Mark the virtual base as seen.
|
||||||
|
Bases.VirtualBases.insert(BaseDecl);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Bases.NonVirtualBases.count(BaseDecl)) {
|
||||||
|
// If this non-virtual base has been seen before, then the class has non-
|
||||||
|
// diamond shaped repeated inheritance.
|
||||||
|
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
|
||||||
|
} else {
|
||||||
|
if (Bases.VirtualBases.count(BaseDecl))
|
||||||
|
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
|
||||||
|
|
||||||
|
// Mark the non-virtual base as seen.
|
||||||
|
Bases.NonVirtualBases.insert(BaseDecl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk all bases.
|
||||||
|
for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(),
|
||||||
|
E = BaseDecl->bases_end(); I != E; ++I)
|
||||||
|
Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
|
||||||
|
|
||||||
|
return Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
|
||||||
|
unsigned Flags = 0;
|
||||||
|
SeenBases Bases;
|
||||||
|
|
||||||
|
// Walk all bases.
|
||||||
|
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
|
||||||
|
E = RD->bases_end(); I != E; ++I)
|
||||||
|
Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
|
||||||
|
|
||||||
|
return Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
|
||||||
|
/// classes with bases that do not satisfy the abi::__si_class_type_info
|
||||||
|
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
|
||||||
|
void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
|
||||||
|
const llvm::Type *UnsignedIntLTy =
|
||||||
|
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
|
||||||
|
|
||||||
|
// Itanium C++ ABI 2.9.5p6c:
|
||||||
|
// __flags is a word with flags describing details about the class
|
||||||
|
// structure, which may be referenced by using the __flags_masks
|
||||||
|
// enumeration. These flags refer to both direct and indirect bases.
|
||||||
|
unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
|
||||||
|
Info.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
|
||||||
|
|
||||||
|
// Itanium C++ ABI 2.9.5p6c:
|
||||||
|
// __base_count is a word with the number of direct proper base class
|
||||||
|
// descriptions that follow.
|
||||||
|
Info.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
|
||||||
|
|
||||||
|
if (!RD->getNumBases())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const llvm::Type *LongLTy =
|
||||||
|
CGM.getTypes().ConvertType(CGM.getContext().LongTy);
|
||||||
|
|
||||||
|
// Now add the base class descriptions.
|
||||||
|
|
||||||
|
// Itanium C++ ABI 2.9.5p6c:
|
||||||
|
// __base_info[] is an array of base class descriptions -- one for every
|
||||||
|
// direct proper base. Each description is of the type:
|
||||||
|
//
|
||||||
|
// struct abi::__base_class_type_info {
|
||||||
|
// public:
|
||||||
|
// const __class_type_info *__base_type;
|
||||||
|
// long __offset_flags;
|
||||||
|
//
|
||||||
|
// enum __offset_flags_masks {
|
||||||
|
// __virtual_mask = 0x1,
|
||||||
|
// __public_mask = 0x2,
|
||||||
|
// __offset_shift = 8
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
|
||||||
|
E = RD->bases_end(); I != E; ++I) {
|
||||||
|
const CXXBaseSpecifier *Base = I;
|
||||||
|
|
||||||
|
// The __base_type member points to the RTTI for the base type.
|
||||||
|
Info.push_back(RTTIBuilder(CGM).BuildType(Base->getType()));
|
||||||
|
|
||||||
|
const CXXRecordDecl *BaseDecl =
|
||||||
|
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||||
|
|
||||||
|
int64_t OffsetFlags = 0;
|
||||||
|
|
||||||
|
// All but the lower 8 bits of __offset_flags are a signed offset.
|
||||||
|
// For a non-virtual base, this is the offset in the object of the base
|
||||||
|
// subobject. For a virtual base, this is the offset in the virtual table of
|
||||||
|
// the virtual base offset for the virtual base referenced (negative).
|
||||||
|
if (Base->isVirtual())
|
||||||
|
OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, BaseDecl);
|
||||||
|
else {
|
||||||
|
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||||
|
OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
OffsetFlags <<= 8;
|
||||||
|
|
||||||
|
// The low-order byte of __offset_flags contains flags, as given by the
|
||||||
|
// masks from the enumeration __offset_flags_masks.
|
||||||
|
if (Base->isVirtual())
|
||||||
|
OffsetFlags |= BCTI_Virtual;
|
||||||
|
if (Base->getAccessSpecifier() == AS_public)
|
||||||
|
OffsetFlags |= BCTI_Public;
|
||||||
|
|
||||||
|
Info.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
|
/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
|
||||||
/// used for pointer types.
|
/// used for pointer types.
|
||||||
void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
|
void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
|
||||||
|
@ -871,7 +846,7 @@ void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
|
||||||
// Itanium C++ ABI 2.9.5p7:
|
// Itanium C++ ABI 2.9.5p7:
|
||||||
// __flags is a flag word describing the cv-qualification and other
|
// __flags is a flag word describing the cv-qualification and other
|
||||||
// attributes of the type pointed to
|
// attributes of the type pointed to
|
||||||
unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
|
unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
|
||||||
|
|
||||||
// Itanium C++ ABI 2.9.5p7:
|
// Itanium C++ ABI 2.9.5p7:
|
||||||
// When the abi::__pbase_type_info is for a direct or indirect pointer to an
|
// When the abi::__pbase_type_info is for a direct or indirect pointer to an
|
||||||
|
@ -897,7 +872,7 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
|
||||||
// Itanium C++ ABI 2.9.5p7:
|
// Itanium C++ ABI 2.9.5p7:
|
||||||
// __flags is a flag word describing the cv-qualification and other
|
// __flags is a flag word describing the cv-qualification and other
|
||||||
// attributes of the type pointed to.
|
// attributes of the type pointed to.
|
||||||
unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
|
unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
|
||||||
|
|
||||||
const RecordType *ClassType = cast<RecordType>(Ty->getClass());
|
const RecordType *ClassType = cast<RecordType>(Ty->getClass());
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,30 @@ public:
|
||||||
const __class_type_info *__base_type;
|
const __class_type_info *__base_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __base_class_type_info {
|
||||||
|
public:
|
||||||
|
const __class_type_info *__base_type;
|
||||||
|
long __offset_flags;
|
||||||
|
|
||||||
|
enum __offset_flags_masks {
|
||||||
|
__virtual_mask = 0x1,
|
||||||
|
__public_mask = 0x2,
|
||||||
|
__offset_shift = 8
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class __vmi_class_type_info : public __class_type_info {
|
||||||
|
public:
|
||||||
|
unsigned int __flags;
|
||||||
|
unsigned int __base_count;
|
||||||
|
__base_class_type_info __base_info[1];
|
||||||
|
|
||||||
|
enum __flags_masks {
|
||||||
|
__non_diamond_repeat_mask = 0x1,
|
||||||
|
__diamond_shaped_mask = 0x2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T> const T& to(const std::type_info &info) {
|
template<typename T> const T& to(const std::type_info &info) {
|
||||||
return static_cast<const T&>(info);
|
return static_cast<const T&>(info);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +79,19 @@ struct VMI2 : virtual A { };
|
||||||
struct VMI3 : A { virtual void f() { } };
|
struct VMI3 : A { virtual void f() { } };
|
||||||
struct VMI4 : A, Empty { };
|
struct VMI4 : A, Empty { };
|
||||||
|
|
||||||
|
struct VMIBase1 { int a; };
|
||||||
|
struct VMIBase2 : VMIBase1 { int a; };
|
||||||
|
struct VMI5 : VMIBase1, VMIBase2 { int a; };
|
||||||
|
|
||||||
|
struct VMIBase3 : virtual VMIBase1 { int a; };
|
||||||
|
struct VMI6 : virtual VMIBase1, VMIBase3 { int a; };
|
||||||
|
|
||||||
|
struct VMI7 : VMIBase1, VMI5, private VMI6 { };
|
||||||
|
|
||||||
#define CHECK(x) if (!(x)) return __LINE__
|
#define CHECK(x) if (!(x)) return __LINE__
|
||||||
#define CHECK_VTABLE(type, vtable) if (&vtable##_type_info_vtable + 2 != (((void **)&(typeid(type)))[0])) return __LINE__
|
#define CHECK_VTABLE(type, vtable) CHECK(&vtable##_type_info_vtable + 2 == (((void **)&(typeid(type)))[0]))
|
||||||
|
#define CHECK_BASE_INFO_TYPE(type, index, base) CHECK(to<__vmi_class_type_info>(typeid(type)).__base_info[(index)].__base_type == &typeid(base))
|
||||||
|
#define CHECK_BASE_INFO_OFFSET_FLAGS(type, index, offset, flags) CHECK(to<__vmi_class_type_info>(typeid(type)).__base_info[(index)].__offset_flags == (((offset) << 8) | (flags)))
|
||||||
|
|
||||||
// CHECK: define i32 @_Z1fv()
|
// CHECK: define i32 @_Z1fv()
|
||||||
int f() {
|
int f() {
|
||||||
|
@ -69,13 +104,16 @@ int f() {
|
||||||
|
|
||||||
// SI1 has a single public base.
|
// SI1 has a single public base.
|
||||||
CHECK_VTABLE(SI1, si_class);
|
CHECK_VTABLE(SI1, si_class);
|
||||||
|
CHECK(to<__si_class_type_info>(typeid(SI1)).__base_type == &typeid(A));
|
||||||
|
|
||||||
// SI2 has a single public empty base.
|
// SI2 has a single public empty base.
|
||||||
CHECK_VTABLE(SI2, si_class);
|
CHECK_VTABLE(SI2, si_class);
|
||||||
|
CHECK(to<__si_class_type_info>(typeid(SI2)).__base_type == &typeid(Empty));
|
||||||
|
|
||||||
// SI3 has a single public empty base. SI3 is dynamic whereas Empty is not, but since Empty is
|
// SI3 has a single public empty base. SI3 is dynamic whereas Empty is not, but since Empty is
|
||||||
// an empty class, it will still be at offset zero.
|
// an empty class, it will still be at offset zero.
|
||||||
CHECK_VTABLE(SI3, si_class);
|
CHECK_VTABLE(SI3, si_class);
|
||||||
|
CHECK(to<__si_class_type_info>(typeid(SI3)).__base_type == &typeid(Empty));
|
||||||
|
|
||||||
// VMI1 has a single base, but it is private.
|
// VMI1 has a single base, but it is private.
|
||||||
CHECK_VTABLE(VMI1, vmi_class);
|
CHECK_VTABLE(VMI1, vmi_class);
|
||||||
|
@ -89,9 +127,34 @@ int f() {
|
||||||
// VMI4 has two bases.
|
// VMI4 has two bases.
|
||||||
CHECK_VTABLE(VMI4, vmi_class);
|
CHECK_VTABLE(VMI4, vmi_class);
|
||||||
|
|
||||||
CHECK(to<__si_class_type_info>(typeid(SI1)).__base_type == &typeid(A));
|
// VMI5 has non-diamond shaped inheritance.
|
||||||
CHECK(to<__si_class_type_info>(typeid(SI2)).__base_type == &typeid(Empty));
|
CHECK_VTABLE(VMI5, vmi_class);
|
||||||
CHECK(to<__si_class_type_info>(typeid(SI3)).__base_type == &typeid(Empty));
|
CHECK(to<__vmi_class_type_info>(typeid(VMI5)).__flags == __vmi_class_type_info::__non_diamond_repeat_mask);
|
||||||
|
CHECK(to<__vmi_class_type_info>(typeid(VMI5)).__base_count == 2);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI5, 0, VMIBase1);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI5, 0, 0, __base_class_type_info::__public_mask);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI5, 1, VMIBase2);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI5, 1, 4, __base_class_type_info::__public_mask);
|
||||||
|
|
||||||
|
// VMI6 has diamond shaped inheritance.
|
||||||
|
CHECK_VTABLE(VMI6, vmi_class);
|
||||||
|
CHECK(to<__vmi_class_type_info>(typeid(VMI6)).__flags == __vmi_class_type_info::__diamond_shaped_mask);
|
||||||
|
CHECK(to<__vmi_class_type_info>(typeid(VMI6)).__base_count == 2);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI6, 0, VMIBase1);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI6, 0, -24, __base_class_type_info::__public_mask | __base_class_type_info::__virtual_mask);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI6, 1, VMIBase3);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI6, 1, 0, __base_class_type_info::__public_mask);
|
||||||
|
|
||||||
|
// VMI7 has both non-diamond and diamond shaped inheritance.
|
||||||
|
CHECK_VTABLE(VMI7, vmi_class);
|
||||||
|
CHECK(to<__vmi_class_type_info>(typeid(VMI7)).__flags == (__vmi_class_type_info::__non_diamond_repeat_mask | __vmi_class_type_info::__diamond_shaped_mask));
|
||||||
|
CHECK(to<__vmi_class_type_info>(typeid(VMI7)).__base_count == 3);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI7, 0, VMIBase1);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 0, 16, __base_class_type_info::__public_mask);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI7, 1, VMI5);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 1, 20, __base_class_type_info::__public_mask);
|
||||||
|
CHECK_BASE_INFO_TYPE(VMI7, 2, VMI6);
|
||||||
|
CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 2, 0, 0);
|
||||||
|
|
||||||
// Pointers to incomplete classes.
|
// Pointers to incomplete classes.
|
||||||
CHECK_VTABLE(Incomplete *, pointer);
|
CHECK_VTABLE(Incomplete *, pointer);
|
||||||
|
|
Loading…
Reference in New Issue