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 {
|
||||
CodeGenModule &CGM; // Per-module state.
|
||||
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;
|
||||
|
||||
/// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
|
||||
|
@ -38,9 +36,14 @@ class RTTIBuilder {
|
|||
void BuildVtablePointer(const Type *Ty);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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
|
||||
/// for pointer types.
|
||||
void BuildPointerTypeInfo(const PointerType *Ty);
|
||||
|
@ -54,25 +57,6 @@ public:
|
|||
: CGM(cgm), VMContext(cgm.getModule().getContext()),
|
||||
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
|
||||
// directly instead.
|
||||
static inline llvm::GlobalVariable::LinkageTypes
|
||||
|
@ -127,145 +111,6 @@ public:
|
|||
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
|
||||
bool DecideHidden(QualType Ty) {
|
||||
// For this type, see if all components are never hidden.
|
||||
|
@ -309,16 +154,7 @@ public:
|
|||
return GetAddrOfExternalRTTIDescriptor(Ty);
|
||||
}
|
||||
|
||||
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::Record:
|
||||
case Type::Pointer:
|
||||
case Type::MemberPointer:
|
||||
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.
|
||||
enum {
|
||||
/// PTI_Const - Type has const qualifier.
|
||||
|
@ -376,6 +187,24 @@ public:
|
|||
/// (in pointer to member).
|
||||
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.
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
// abi::__fundamental_type_info
|
||||
// abi::__fundamental_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
|
||||
break;
|
||||
|
||||
case Type::ConstantArray:
|
||||
case Type::IncompleteArray:
|
||||
// abi::__array_type_info
|
||||
// abi::__array_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
|
||||
break;
|
||||
|
||||
case Type::FunctionNoProto:
|
||||
case Type::FunctionProto:
|
||||
// abi::__function_type_info
|
||||
// abi::__function_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
|
||||
break;
|
||||
|
||||
case Type::Enum:
|
||||
// abi::__enum_type_info
|
||||
// abi::__enum_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
|
||||
break;
|
||||
|
||||
case Type::Record: {
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
|
||||
|
||||
if (!RD->getNumBases()) {
|
||||
// abi::__class_type_info
|
||||
// abi::__class_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
|
||||
} else if (CanUseSingleInheritance(RD)) {
|
||||
// abi::__si_class_type_info;
|
||||
// abi::__si_class_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
|
||||
} else {
|
||||
assert(false && "Should not get here!");
|
||||
// abi::__vmi_class_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Pointer:
|
||||
// abi::__pointer_type_info
|
||||
// abi::__pointer_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
|
||||
break;
|
||||
|
||||
case Type::MemberPointer:
|
||||
// abi::__pointer_to_member_type_info
|
||||
// abi::__pointer_to_member_type_info.
|
||||
VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
|
||||
break;
|
||||
}
|
||||
|
@ -804,10 +635,12 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (CanUseSingleInheritance(RD)) {
|
||||
if (CanUseSingleInheritance(RD))
|
||||
BuildSIClassTypeInfo(RD);
|
||||
break;
|
||||
}
|
||||
else
|
||||
BuildVMIClassTypeInfo(RD);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Pointer:
|
||||
|
@ -839,9 +672,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
|
|||
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.
|
||||
static unsigned DetermineQualifierFlags(Qualifiers Quals) {
|
||||
static unsigned ComputeQualifierFlags(Qualifiers Quals) {
|
||||
unsigned Flags = 0;
|
||||
|
||||
if (Quals.hasConst())
|
||||
|
@ -863,6 +696,148 @@ void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
|
|||
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,
|
||||
/// used for pointer types.
|
||||
void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
|
||||
|
@ -871,7 +846,7 @@ void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
|
|||
// 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());
|
||||
unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
|
||||
|
||||
// Itanium C++ ABI 2.9.5p7:
|
||||
// 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:
|
||||
// __flags is a flag word describing the cv-qualification and other
|
||||
// attributes of the type pointed to.
|
||||
unsigned Flags = DetermineQualifierFlags(PointeeTy.getQualifiers());
|
||||
unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
|
||||
|
||||
const RecordType *ClassType = cast<RecordType>(Ty->getClass());
|
||||
|
||||
|
|
|
@ -752,10 +752,10 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
|
|||
}
|
||||
|
||||
const CXXRecordDecl *DerivedDecl =
|
||||
cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
|
||||
cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
|
||||
|
||||
const CXXRecordDecl *BaseDecl =
|
||||
cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
|
||||
cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
|
||||
|
||||
return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,30 @@ public:
|
|||
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) {
|
||||
return static_cast<const T&>(info);
|
||||
}
|
||||
|
@ -55,8 +79,19 @@ struct VMI2 : virtual A { };
|
|||
struct VMI3 : A { virtual void f() { } };
|
||||
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_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()
|
||||
int f() {
|
||||
|
@ -69,13 +104,16 @@ int f() {
|
|||
|
||||
// SI1 has a single public base.
|
||||
CHECK_VTABLE(SI1, si_class);
|
||||
CHECK(to<__si_class_type_info>(typeid(SI1)).__base_type == &typeid(A));
|
||||
|
||||
// SI2 has a single public empty base.
|
||||
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
|
||||
// an empty class, it will still be at offset zero.
|
||||
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.
|
||||
CHECK_VTABLE(VMI1, vmi_class);
|
||||
|
@ -88,10 +126,35 @@ int f() {
|
|||
|
||||
// VMI4 has two bases.
|
||||
CHECK_VTABLE(VMI4, vmi_class);
|
||||
|
||||
// VMI5 has non-diamond shaped inheritance.
|
||||
CHECK_VTABLE(VMI5, vmi_class);
|
||||
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);
|
||||
|
||||
CHECK(to<__si_class_type_info>(typeid(SI1)).__base_type == &typeid(A));
|
||||
CHECK(to<__si_class_type_info>(typeid(SI2)).__base_type == &typeid(Empty));
|
||||
CHECK(to<__si_class_type_info>(typeid(SI3)).__base_type == &typeid(Empty));
|
||||
// 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.
|
||||
CHECK_VTABLE(Incomplete *, pointer);
|
||||
|
|
Loading…
Reference in New Issue