Fix a bunch of bugs with VMI RTTI building, and add a whole bunch of tests.

llvm-svn: 92319
This commit is contained in:
Anders Carlsson 2009-12-30 23:47:56 +00:00
parent da3ddfce43
commit a442499072
3 changed files with 257 additions and 219 deletions

View File

@ -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());

View File

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