[cfe-commits] r92319 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CGVtable.cpp test/CodeGenCXX/rtti-layout.cpp
Anders Carlsson
andersca at mac.com
Wed Dec 30 15:47:56 PST 2009
Author: andersca
Date: Wed Dec 30 17:47:56 2009
New Revision: 92319
URL: http://llvm.org/viewvc/llvm-project?rev=92319&view=rev
Log:
Fix a bunch of bugs with VMI RTTI building, and add a whole bunch of tests.
Modified:
cfe/trunk/lib/CodeGen/CGRTTI.cpp
cfe/trunk/lib/CodeGen/CGVtable.cpp
cfe/trunk/test/CodeGenCXX/rtti-layout.cpp
Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=92319&r1=92318&r2=92319&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Wed Dec 30 17:47:56 2009
@@ -21,10 +21,8 @@
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 @@
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 @@
: 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 @@
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 @@
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 @@
}
}
- /// 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 @@
/// (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 @@
// 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 @@
break;
}
- if (CanUseSingleInheritance(RD)) {
+ if (CanUseSingleInheritance(RD))
BuildSIClassTypeInfo(RD);
- break;
- }
+ else
+ BuildVMIClassTypeInfo(RD);
+
+ break;
}
case Type::Pointer:
@@ -839,9 +672,9 @@
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 @@
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 @@
// 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 @@
// 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());
Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=92319&r1=92318&r2=92319&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Dec 30 17:47:56 2009
@@ -752,10 +752,10 @@
}
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);
}
Modified: cfe/trunk/test/CodeGenCXX/rtti-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-layout.cpp?rev=92319&r1=92318&r2=92319&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/rtti-layout.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/rtti-layout.cpp Wed Dec 30 17:47:56 2009
@@ -38,6 +38,30 @@
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 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 @@
// 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 @@
// 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);
More information about the cfe-commits
mailing list