diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index b91cc8cf41ba..a440e65fd87b 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -21,10 +21,8 @@ namespace { class RTTIBuilder { CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; - const llvm::Type *Int8PtrTy; - llvm::SmallSet SeenVBase; - llvm::SmallSet SeenBase; + const llvm::Type *Int8PtrTy; std::vector 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(i->getType()->getAs()->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(i->getType()->getAs()->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(BaseType->getAs()->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(&Type); - - const CXXRecordDecl *RD = cast(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(cast(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 NonVirtualBases; + llvm::SmallPtrSet 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(Base->getType()->getAs()->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(Base->getType()->getAs()->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(Ty->getClass()); diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp index 0552ae7c1386..7930f7186da5 100644 --- a/clang/lib/CodeGen/CGVtable.cpp +++ b/clang/lib/CodeGen/CGVtable.cpp @@ -752,10 +752,10 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, } const CXXRecordDecl *DerivedDecl = - cast(cast(CanDerivedType)->getDecl()); + cast(cast(CanDerivedType)->getDecl()); const CXXRecordDecl *BaseDecl = - cast(cast(CanBaseType)->getDecl()); + cast(cast(CanBaseType)->getDecl()); return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); } diff --git a/clang/test/CodeGenCXX/rtti-layout.cpp b/clang/test/CodeGenCXX/rtti-layout.cpp index 6b3b26747ffe..1ad87fbc7ef7 100644 --- a/clang/test/CodeGenCXX/rtti-layout.cpp +++ b/clang/test/CodeGenCXX/rtti-layout.cpp @@ -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 const T& to(const std::type_info &info) { return static_cast(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);