Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2262,12 +2262,12 @@ uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) { MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "\01??_R1"; - Mangler.mangleNumber(NVOffset); - Mangler.mangleNumber(VBPtrOffset); - Mangler.mangleNumber(VBTableOffset); - Mangler.mangleNumber(Flags); + Mangler.mangleNumber((int)NVOffset); + Mangler.mangleNumber((int)VBPtrOffset); + Mangler.mangleNumber((int)VBTableOffset); + Mangler.mangleNumber((int)Flags); Mangler.mangleName(Derived); - Mangler.getStream() << "@8"; + Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray( @@ -2275,7 +2275,7 @@ MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "\01??_R2"; Mangler.mangleName(Derived); - Mangler.getStream() << "@8"; + Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor( @@ -2283,7 +2283,7 @@ MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "\01??_R3"; Mangler.mangleName(Derived); - Mangler.getStream() << "@8"; + Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator( Index: lib/CodeGen/CGRTTI.cpp =================================================================== --- lib/CodeGen/CGRTTI.cpp +++ lib/CodeGen/CGRTTI.cpp @@ -990,3 +990,382 @@ for (unsigned i = 0; i < llvm::array_lengthof(FundamentalTypes); ++i) EmitFundamentalRTTIDescriptor(FundamentalTypes[i]); } + +/// \brief A Helper class for building MS RTTI types. +struct MSRTTIBuilder { + /// \brief A Helper class that stores information about a base class for the + /// sake of generating BaseClassDescriptor structs. + struct BaseClass { + enum { + IsPrivateOnPath = 1 | 8, + IsAmbiguous = 2, + IsPrivate = 4, + IsVirtual = 16, + HasHierarchyDescriptor = 64 + }; + BaseClass(const CXXRecordDecl *Record, const BaseClass *Parent, + const CXXBaseSpecifier *Specifier); + const CXXRecordDecl *RD, *VirtualRoot; + int Flags, NumBases, OffsetInVbase; + }; + + MSRTTIBuilder(CodeGenModule &CGM); + llvm::Constant *getTypeDescriptor(QualType Type); + llvm::GlobalVariable *getClassHierarchyDescriptor(const CXXRecordDecl *RD); + llvm::GlobalVariable *getCompleteObjectLocator(const CXXRecordDecl *RD, + const VPtrInfo *Info); + +private: + llvm::StructType *getTypeDescriptorType(StringRef Str); + bool DeclareCompleteObjectLocator(); + bool DeclareClassHierarchyDescriptor(); + void WalkClassHierarchy(const CXXRecordDecl *Record, + const BaseClass *Parent = 0, + const CXXBaseSpecifier *Specifier = 0); + void DetectAmbiguousBases(); + void DeclareBaseClassArray(); + llvm::GlobalVariable *CreateBaseClassDescriptor(const BaseClass& Base); + void InitializeBaseClassArray(); + void InitializeClassHierarchyDescriptor(); + void InitializeCompleteObjectLocator(); + + // Members with full object lifetime. + CodeGenModule &CGM; + ASTContext &Context; + llvm::LLVMContext &VMContext; + llvm::Module &Module; + MicrosoftMangleContext &Mangler; + MicrosoftVTableContext &VTableContext; + llvm::StructType *BaseClassDescriptorType; + llvm::StructType *ClassHierarchyDescriptorType; + llvm::StructType *CompleteObjectLocatorType; + + // Helper members with lifetime of getCompleteObjectLocator. + const CXXRecordDecl *RD; + const VPtrInfo *Info; + llvm::GlobalVariable::LinkageTypes Linkage; + llvm::GlobalVariable *CompleteObjectLocator; + llvm::GlobalVariable *ClassHierarchyDescriptor; + llvm::GlobalVariable *BaseClassArray; + llvm::ArrayType *BaseClassArrayType; + SmallVector Bases; +}; + +// Used by MSRTTIBuilder::BaseClass::BaseClass +static int countNonVirtualBases(const CXXRecordDecl *RD) { + int Count = 0; + for (const CXXBaseSpecifier &Base : RD->bases()) + Count += 1 + countNonVirtualBases(Base.getType()->getAsCXXRecordDecl()); + return Count; +} + +MSRTTIBuilder::BaseClass::BaseClass(const CXXRecordDecl *RD, + const BaseClass *Parent, + const CXXBaseSpecifier *Specifier) + : RD(RD), Flags(HasHierarchyDescriptor), VirtualRoot(0), OffsetInVbase(0), + NumBases(countNonVirtualBases(RD)) { + if (!Parent) + return; + if (Specifier->getAccessSpecifier() != AS_public) + Flags |= IsPrivate | IsPrivateOnPath; + if (Specifier->isVirtual()) { + Flags |= IsVirtual; + VirtualRoot = RD; + } else { + if (Parent->Flags & IsPrivateOnPath) + Flags |= IsPrivateOnPath; + VirtualRoot = Parent->VirtualRoot; + OffsetInVbase = Parent->OffsetInVbase + + RD->getASTContext() + .getASTRecordLayout(Parent->RD) + .getBaseClassOffset(RD) + .getQuantity(); + } +} + +MSRTTIBuilder::MSRTTIBuilder(CodeGenModule &CGM) + : CGM(CGM), Context(CGM.getContext()), VMContext(CGM.getLLVMContext()), + Module(CGM.getModule()), + Mangler(cast(CGM.getCXXABI().getMangleContext())), + VTableContext(CGM.getMicrosoftVTableContext()) { + // Forward declare the ClassHierarchyDescriptor because of a cycle in the + // rtti types. + ClassHierarchyDescriptorType = + llvm::StructType::create(VMContext, "MSRTTIClassHierarchyDescriptor"); + // Describe the BaseClassDescriptor Type. + SmallVector FieldTypes; + FieldTypes.push_back(CGM.Int8PtrTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(ClassHierarchyDescriptorType->getPointerTo()); + BaseClassDescriptorType = llvm::StructType::create( + VMContext, FieldTypes, "MSRTTIBaseClassDescriptor"); + // Describe the ClassHierarchyDescriptor. + FieldTypes.clear(); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(BaseClassDescriptorType->getPointerTo()->getPointerTo()); + ClassHierarchyDescriptorType->setBody(FieldTypes); + // Describe the CompleteObjectLocator. + FieldTypes.clear(); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.Int8PtrTy); + FieldTypes.push_back(ClassHierarchyDescriptorType->getPointerTo()); + CompleteObjectLocatorType = llvm::StructType::create( + VMContext, FieldTypes, "MSRTTICompleteObjectLocator"); +} + +// Gets a type descriptor. Returns a llvm::Constant * rather than a +// llvm::GlobalVariable * because different type descriptors have different +// types, and need to be abstracted. They are abstracting by casting the +// address to an Int8PtrTy. +llvm::Constant *MSRTTIBuilder::getTypeDescriptor(QualType Type) { + SmallString<256> TypeDescriptorMangledName, TypeInfoString; + llvm::raw_svector_ostream Out(TypeDescriptorMangledName); + Mangler.mangleCXXRTTI(Type, Out); + Out.flush(); + llvm::GlobalVariable *TypeDescriptor = + Module.getNamedGlobal(TypeDescriptorMangledName); + if (TypeDescriptor) + return llvm::ConstantExpr::getBitCast(TypeDescriptor, CGM.Int8PtrTy); + llvm::raw_svector_ostream Out2 = llvm::raw_svector_ostream(TypeInfoString); + Mangler.mangleCXXRTTIName(Type, Out2); + Out2.flush(); + llvm::StructType *TypeDescriptorType = getTypeDescriptorType(TypeInfoString); + SmallVector Fields; + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, 0)); // VFPtr + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, 0)); // Runtime data + Fields.push_back( + llvm::ConstantDataArray::getString(VMContext, TypeInfoString)); + TypeDescriptor = new llvm::GlobalVariable( + Module, TypeDescriptorType, /*Constant=*/true, + getTypeInfoLinkage(CGM, Type), + llvm::ConstantStruct::get(TypeDescriptorType, Fields), + TypeDescriptorMangledName.c_str()); + return llvm::ConstantExpr::getBitCast(TypeDescriptor, CGM.Int8PtrTy); +} + +llvm::StructType *MSRTTIBuilder::getTypeDescriptorType(StringRef Str) { + llvm::SmallString<32> TDTypeName = "MSRTTITypeDescriptor"; + TDTypeName += Str.size(); + llvm::StructType *TypeDescriptorType = Module.getTypeByName(TDTypeName); + if (TypeDescriptorType) + return TypeDescriptorType; + SmallVector FieldTypes; + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(CGM.IntTy); + FieldTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty, Str.size() + 1)); + return llvm::StructType::create(VMContext, FieldTypes, TDTypeName); +} + +llvm::GlobalVariable * +MSRTTIBuilder::getClassHierarchyDescriptor(const CXXRecordDecl *RD) { + this->RD = RD; + Bases.clear(); + Linkage = CGM.getVTableLinkage(RD); + if (!DeclareClassHierarchyDescriptor()) + return ClassHierarchyDescriptor; + WalkClassHierarchy(RD); + DetectAmbiguousBases(); + DeclareBaseClassArray(); + InitializeBaseClassArray(); + InitializeClassHierarchyDescriptor(); + return ClassHierarchyDescriptor; +} + +llvm::GlobalVariable * +MSRTTIBuilder::getCompleteObjectLocator(const CXXRecordDecl *RD, + const VPtrInfo *Info) { + this->RD = RD; + this->Info = Info; + Linkage = CGM.getVTableLinkage(RD); + if (!DeclareCompleteObjectLocator()) + return CompleteObjectLocator; + getClassHierarchyDescriptor(RD); + InitializeCompleteObjectLocator(); + return CompleteObjectLocator; +} + +bool MSRTTIBuilder::DeclareCompleteObjectLocator() { + SmallString<256> MangledName; + llvm::raw_svector_ostream Out(MangledName); + Mangler.mangleCXXRTTICompleteObjectLocator(RD, Info->MangledPath, Out); + Out.flush(); + CompleteObjectLocator = Module.getNamedGlobal(MangledName); + if (CompleteObjectLocator) + return false; + CompleteObjectLocator = + new llvm::GlobalVariable(Module, CompleteObjectLocatorType, + /*Constant=*/true, Linkage, + /*Initializer=*/0, MangledName.c_str()); + return true; +} + +bool MSRTTIBuilder::DeclareClassHierarchyDescriptor() { + SmallString<256> MangledName; + llvm::raw_svector_ostream Out(MangledName); + Mangler.mangleCXXRTTIClassHierarchyDescriptor(RD, Out); + Out.flush(); + ClassHierarchyDescriptor = Module.getNamedGlobal(MangledName); + if (ClassHierarchyDescriptor) + return false; + ClassHierarchyDescriptor = new llvm::GlobalVariable( + Module, ClassHierarchyDescriptorType, + /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str()); + return true; +} + +void MSRTTIBuilder::WalkClassHierarchy(const CXXRecordDecl *Record, + const BaseClass *Parent, + const CXXBaseSpecifier *Specifier) { + BaseClass BaseClass(Record, Parent, Specifier); + Bases.push_back(BaseClass); + for (const CXXBaseSpecifier &Base : Record->bases()) + WalkClassHierarchy(Base.getType()->getAsCXXRecordDecl(), + &BaseClass, &Base); +} + +void MSRTTIBuilder::DetectAmbiguousBases() { + llvm::SmallPtrSet VirtualBases; + llvm::SmallPtrSet UniqueBases; + llvm::SmallPtrSet AmbiguousBases; + for (size_t i = 0, e = Bases.size(); i != e; i++) { + BaseClass &Base = Bases[i]; + if (Base.Flags & BaseClass::IsVirtual && !VirtualBases.insert(Base.RD)) + i += Base.NumBases; + else if (!UniqueBases.insert(Base.RD)) + AmbiguousBases.insert(Base.RD); + } + for (BaseClass &Base : Bases) + if (AmbiguousBases.count(Base.RD)) + Base.Flags |= BaseClass::IsAmbiguous; +} + +void MSRTTIBuilder::DeclareBaseClassArray() { + SmallString<256> MangledName; + llvm::raw_svector_ostream Out(MangledName); + Mangler.mangleCXXRTTIBaseClassArray(RD, Out); + Out.flush(); + // We have Bases.size() + 1 because the arrays have some 0 padding at the end. + BaseClassArrayType = llvm::ArrayType::get( + BaseClassDescriptorType->getPointerTo(), Bases.size() + 1); + // TODO: base class arrays need one tail byte. + BaseClassArray = new llvm::GlobalVariable( + Module, BaseClassArrayType, /*Constant=*/true, Linkage, + /*Initializer=*/0, MangledName.c_str()); +} + +llvm::GlobalVariable * +MSRTTIBuilder::CreateBaseClassDescriptor(const BaseClass &Base) { + int OffsetInVBTable = 0; + int VBPtrOffset = -1; + const CXXRecordDecl *Root = RD; + if (Base.VirtualRoot) { + OffsetInVBTable = VTableContext.getVBTableIndex(RD, Base.VirtualRoot) * 4; + VBPtrOffset = Context.getASTRecordLayout(RD).getVBPtrOffset().getQuantity(); + Root = Base.VirtualRoot; + } + SmallString<256> MangledName; + llvm::raw_svector_ostream Out(MangledName); + Mangler.mangleCXXRTTIBaseClassDescriptor(Base.RD, Base.OffsetInVbase, + VBPtrOffset, OffsetInVBTable, + Base.Flags, Out); + Out.flush(); + llvm::GlobalVariable *BaseClassDescriptor = + Module.getNamedGlobal(MangledName); + if (BaseClassDescriptor) + return BaseClassDescriptor; + BaseClassDescriptor = new llvm::GlobalVariable( + Module, BaseClassDescriptorType, /*Constant=*/true, Linkage, + /*Initializer=*/0, MangledName.c_str()); + SmallVector Fields; + Fields.push_back(getTypeDescriptor(Context.getTypeDeclType(Base.RD))); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Base.NumBases)); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Base.OffsetInVbase)); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset)); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable)); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Base.Flags)); + Fields.push_back(MSRTTIBuilder(*this).getClassHierarchyDescriptor(Base.RD)); + BaseClassDescriptor->setInitializer( + llvm::ConstantStruct::get(BaseClassDescriptorType, Fields)); + return BaseClassDescriptor; +} + +void MSRTTIBuilder::InitializeBaseClassArray() { + SmallVector BaseClassArrayData; + for (BaseClass &Base : Bases) + BaseClassArrayData.push_back(CreateBaseClassDescriptor(Base)); + // cl.exe pads the base class array with 1 (in 32 bit mode) or 4 (in 64 bit + // mode) bytes of padding. We provide a pointer sized amount of padding. The + // sections have pointer alignment and are marked pick-any so it shouldn't + // matter. + BaseClassArrayData.push_back( + llvm::ConstantPointerNull::get(BaseClassDescriptorType->getPointerTo())); + BaseClassArray->setInitializer( + llvm::ConstantArray::get(BaseClassArrayType, BaseClassArrayData)); +} + +void MSRTTIBuilder::InitializeClassHierarchyDescriptor() { + enum { + HasBranchingHierarchy = 1, + HasVirtualBranchingHierarchy = 2, + HasAmbiguousBases = 4 + }; + int Flags = 0; + for (auto Base : Bases) { + if (Base.RD->getNumBases() > 1) Flags |= HasBranchingHierarchy; + if (Base.Flags & BaseClass::IsAmbiguous) Flags |= HasAmbiguousBases; + } + if (Flags & HasBranchingHierarchy && RD->getNumVBases() != 0) + Flags |= HasVirtualBranchingHierarchy; + llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0), + llvm::ConstantInt::get(CGM.IntTy, 0)}; + SmallVector Fields; + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, 0)); // Unknown + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Flags)); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, (int)Bases.size())); + Fields.push_back(llvm::ConstantExpr::getInBoundsGetElementPtr( + BaseClassArray, llvm::ArrayRef(GEPIndices))); + ClassHierarchyDescriptor->setInitializer( + llvm::ConstantStruct::get(ClassHierarchyDescriptorType, Fields)); +} + +void MSRTTIBuilder::InitializeCompleteObjectLocator() { + int VFPtrOffset = 0; + // The offset includes the vtordisp if one exists. + if (const CXXRecordDecl *VBase = Info->getVBaseWithVPtr()) + if (Context.getASTRecordLayout(RD) + .getVBaseOffsetsMap() + .find(VBase) + ->second.hasVtorDisp()) + VFPtrOffset = Info->NonVirtualOffset.getQuantity() + 4; + SmallVector Fields; + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, 0)); // IsDeltaEncoded + Fields.push_back( + llvm::ConstantInt::get(CGM.IntTy, Info->FullOffsetInMDC.getQuantity())); + Fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset)); + Fields.push_back(getTypeDescriptor(Context.getTypeDeclType(RD))); + Fields.push_back(ClassHierarchyDescriptor); + CompleteObjectLocator->setInitializer( + llvm::ConstantStruct::get(CompleteObjectLocatorType, Fields)); +} + +llvm::Constant *CodeGenModule::getMSTypeDescriptor(QualType Type) { + if (!MSRTTIBuilderObject) + MSRTTIBuilderObject = new MSRTTIBuilder(*this); + return MSRTTIBuilderObject->getTypeDescriptor(Type); +} + +llvm::GlobalVariable * +CodeGenModule::getMSCompleteObjectLocator(const CXXRecordDecl *RD, + const VPtrInfo *Info) { + if (!MSRTTIBuilderObject) + MSRTTIBuilderObject = new MSRTTIBuilder(*this); + return MSRTTIBuilderObject->getCompleteObjectLocator(RD, Info); +} Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -33,6 +33,8 @@ #include "llvm/IR/ValueHandle.h" #include "llvm/Transforms/Utils/SpecialCaseList.h" +struct MSRTTIBuilder; + namespace llvm { class Module; class Constant; @@ -244,6 +246,7 @@ const TargetInfo &Target; std::unique_ptr ABI; llvm::LLVMContext &VMContext; + MSRTTIBuilder* MSRTTIBuilderObject; CodeGenTBAA *TBAA; @@ -710,7 +713,13 @@ /// The type of a generic block literal. llvm::Type *getGenericBlockLiteralType(); - /// Gets the address of a block which requires no captures. + /// Microsoft RTTI generators. + llvm::Constant *getMSTypeDescriptor(QualType Ty); + llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD, + const VPtrInfo *Info); + + /// GetAddrOfGlobalBlock - Gets the address of a block which + /// requires no captures. llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); /// Return a pointer to a constant CFString object for the given string. Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -81,11 +81,11 @@ TheTargetCodeGenInfo(0), Types(*this), VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), OpenMPRuntime(nullptr), CUDARuntime(0), DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0), RRData(0), PGOReader(nullptr), - CFConstantStringClassRef(0), - ConstantStringClassRef(0), NSConstantStringType(0), - NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0), - BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0), - LifetimeStartFn(0), LifetimeEndFn(0), + CFConstantStringClassRef(0), ConstantStringClassRef(0), + NSConstantStringType(0), NSConcreteGlobalBlock(0), + NSConcreteStackBlock(0), BlockObjectAssign(0), BlockObjectDispose(0), + BlockDescriptorType(0), GenericBlockLiteralType(0), + MSRTTIBuilderObject(0), LifetimeStartFn(0), LifetimeEndFn(0), SanitizerBlacklist( llvm::SpecialCaseList::createOrDie(CGO.SanitizerBlacklistFile)), SanOpts(SanitizerBlacklist->isIn(M) ? SanitizerOptions::Disabled Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -896,14 +896,15 @@ VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD); llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); - for (VPtrInfoVector::iterator I = VFPtrs.begin(), E = VFPtrs.end(); I != E; - ++I) { - llvm::GlobalVariable *VTable = getAddrOfVTable(RD, (*I)->FullOffsetInMDC); + for (VPtrInfo *Info : VFPtrs) { + llvm::GlobalVariable *VTable = getAddrOfVTable(RD, (Info)->FullOffsetInMDC); if (VTable->hasInitializer()) continue; + if (getContext().getLangOpts().RTTI) + CGM.getMSCompleteObjectLocator(RD, Info); const VTableLayout &VTLayout = - VFTContext.getVFTableLayout(RD, (*I)->FullOffsetInMDC); + VFTContext.getVFTableLayout(RD, (Info)->FullOffsetInMDC); llvm::Constant *Init = CGVT.CreateVTableInitializer( RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(), Index: test/CodeGenCXX/microsoft-abi-rtti.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/microsoft-abi-rtti.cpp @@ -0,0 +1,147 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 2>/dev/null %s | FileCheck %s + +struct N {}; +struct M : private N {}; +struct X { virtual void f() {} }; +class Z { virtual void f() {} }; +class V : public X { virtual void f() {} }; +class W : M, virtual V { public: virtual void f() {} }; +class Y : Z, W, virtual V { public: virtual void g() {} } y; + +struct A {}; +struct B : A {}; +struct C : B { virtual void f() {} } c; + +struct X1 { virtual void f() {} }; +struct V1 : X1 {}; +struct W1 : virtual V1 {}; +struct Y1 : W1, virtual V1 {} y1; + +struct A1 { virtual void f() {} }; +struct B1 : virtual A1 { virtual void f() {} B1() {} } b1; + +struct Z2 { virtual void f() {} }; +struct Y2 { virtual void f() {} }; +struct A2 : Z2, Y2 {}; +struct B2 : virtual A2 { B2() {} virtual void f() {} } b2; + +// CHECK: @"\01??_R4B2@@6BZ2@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 8, i32 4, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUB2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3B2@@8" } +// CHECK: @"\01??_R3B2@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 3, i32 4, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([5 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2B2@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2B2@@8" = linkonce_odr constant [5 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@B2@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FA@A2@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3EA@Z2@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13A@3EA@Y2@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@B2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUB2@@@8" to i8*), i32 3, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3B2@@8" } +// CHECK: @"\01??_R0?AUB2@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUB2@@\00" } +// CHECK: @"\01??_R1A@A@3FA@A2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA2@@@8" to i8*), i32 2, i32 0, i32 0, i32 4, i32 80, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A2@@8" } +// CHECK: @"\01??_R0?AUA2@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUA2@@\00" } +// CHECK: @"\01??_R3A2@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 1, i32 3, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([4 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2A2@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2A2@@8" = linkonce_odr constant [4 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@A2@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Z2@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EA@Y2@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@A2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA2@@@8" to i8*), i32 2, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A2@@8" } +// CHECK: @"\01??_R1A@?0A@EA@Z2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUZ2@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z2@@8" } +// CHECK: @"\01??_R0?AUZ2@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUZ2@@\00" } +// CHECK: @"\01??_R3Z2@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2Z2@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2Z2@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Z2@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R13?0A@EA@Y2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY2@@@8" to i8*), i32 0, i32 4, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y2@@8" } +// CHECK: @"\01??_R0?AUY2@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUY2@@\00" } +// CHECK: @"\01??_R3Y2@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2Y2@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2Y2@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Y2@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@Y2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY2@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y2@@8" } +// CHECK: @"\01??_R1A@A@3EA@Z2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUZ2@@@8" to i8*), i32 0, i32 0, i32 0, i32 4, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z2@@8" } +// CHECK: @"\01??_R13A@3EA@Y2@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY2@@@8" to i8*), i32 0, i32 4, i32 0, i32 4, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y2@@8" } +// CHECK: @"\01??_R4B2@@6BY2@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 12, i32 8, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUB2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3B2@@8" } +// CHECK: @"\01??_R4A2@@6BZ2@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3A2@@8" } +// CHECK: @"\01??_R4A2@@6BY2@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 4, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3A2@@8" } +// CHECK: @"\01??_R4Y2@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y2@@8" } +// CHECK: @"\01??_R4Z2@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUZ2@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z2@@8" } + +// CHECK: @"\01??_R4B1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 8, i32 4, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUB1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3B1@@8" } +// CHECK: @"\01??_R3B1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 2, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([3 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2B1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2B1@@8" = linkonce_odr constant [3 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@B1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FA@A1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@B1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUB1@@@8" to i8*), i32 1, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3B1@@8" } +// CHECK: @"\01??_R0?AUB1@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUB1@@\00" } +// CHECK: @"\01??_R1A@A@3FA@A1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA1@@@8" to i8*), i32 0, i32 0, i32 0, i32 4, i32 80, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A1@@8" } +// CHECK: @"\01??_R0?AUA1@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUA1@@\00" } +// CHECK: @"\01??_R3A1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2A1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2A1@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@A1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@A1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA1@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A1@@8" } +// CHECK: @"\01??_R4A1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUA1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3A1@@8" } + +// CHECK: @"\01??_R4Y1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 4, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y1@@8" } +// CHECK: @"\01??_R3Y1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 3, i32 6, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([7 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2Y1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2Y1@@8" = linkonce_odr constant [7 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Y1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@W1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FA@V1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3EA@X1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FA@V1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3EA@X1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@Y1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUY1@@@8" to i8*), i32 5, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y1@@8" } +// CHECK: @"\01??_R0?AUY1@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUY1@@\00" } +// CHECK: @"\01??_R1A@?0A@EA@W1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUW1@@@8" to i8*), i32 2, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3W1@@8" } +// CHECK: @"\01??_R0?AUW1@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUW1@@\00" } +// CHECK: @"\01??_R3W1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 3, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([4 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2W1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2W1@@8" = linkonce_odr constant [4 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@W1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FA@V1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3EA@X1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@A@3FA@V1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUV1@@@8" to i8*), i32 1, i32 0, i32 0, i32 4, i32 80, %MSRTTIClassHierarchyDescriptor* @"\01??_R3V1@@8" } +// CHECK: @"\01??_R0?AUV1@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\08" { i32 0, i32 0, [9 x i8] c".?AUV1@@\00" } +// CHECK: @"\01??_R3V1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 2, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([3 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2V1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2V1@@8" = linkonce_odr constant [3 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@V1@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@X1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@V1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUV1@@@8" to i8*), i32 1, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3V1@@8" } +// CHECK: @"\01??_R1A@?0A@EA@X1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUX1@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3X1@@8" } +// CHECK: @"\01??_R3X1@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2X1@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2X1@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@X1@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@A@3EA@X1@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUX1@@@8" to i8*), i32 0, i32 0, i32 0, i32 4, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3X1@@8" } +// CHECK: @"\01??_R4W1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 4, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUW1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3W1@@8" } +// CHECK: @"\01??_R4V1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUV1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3V1@@8" } +// CHECK: @"\01??_R4X1@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\08"* @"\01??_R0?AUX1@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3X1@@8" } +// CHECK: @"\01??_R4C@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUC@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3C@@8" } +// CHECK: @"\01??_R3C@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 3, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([4 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2C@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2C@@8" = linkonce_odr constant [4 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@C@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EA@B@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EA@A@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@C@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUC@@@8" to i8*), i32 2, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3C@@8" } +// CHECK: @"\01??_R0?AUC@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUC@@\00" } +// CHECK: @"\01??_R13?0A@EA@B@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i32 1, i32 4, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3B@@8" } +// CHECK: @"\01??_R0?AUB@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUB@@\00" } +// CHECK: @"\01??_R3B@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 2, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([3 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2B@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2B@@8" = linkonce_odr constant [3 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@B@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@A@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@B@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i32 1, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3B@@8" } +// CHECK: @"\01??_R1A@?0A@EA@A@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A@@8" } +// CHECK: @"\01??_R0?AUA@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUA@@\00" } +// CHECK: @"\01??_R3A@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2A@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2A@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@A@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R13?0A@EA@A@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i32 0, i32 4, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3A@@8" } +// CHECK: @"\01??_R4Y@@6BZ@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVY@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y@@8" } +// CHECK: @"\01??_R3Y@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 3, i32 9, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([10 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2Y@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2Y@@8" = linkonce_odr constant [10 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Y@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EN@Z@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EN@W@@8", %MSRTTIBaseClassDescriptor* @"\01??_R17?0A@EN@M@@8", %MSRTTIBaseClassDescriptor* @"\01??_R17?0A@EN@N@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@33FN@V@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@33EJ@X@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@33FN@V@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@33EJ@X@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@Y@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVY@@@8" to i8*), i32 8, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y@@8" } +// CHECK: @"\01??_R0?AVY@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AVY@@\00" } +// CHECK: @"\01??_R1A@?0A@EN@Z@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVZ@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z@@8" } +// CHECK: @"\01??_R0?AVZ@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AVZ@@\00" } +// CHECK: @"\01??_R3Z@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2Z@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2Z@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@Z@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@Z@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVZ@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z@@8" } +// CHECK: @"\01??_R13?0A@EN@W@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVW@@@8" to i8*), i32 4, i32 4, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3W@@8" } +// CHECK: @"\01??_R0?AVW@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AVW@@\00" } +// CHECK: @"\01??_R3W@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 3, i32 5, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([6 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2W@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2W@@8" = linkonce_odr constant [6 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@W@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EN@M@@8", %MSRTTIBaseClassDescriptor* @"\01??_R13?0A@EN@N@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3FN@V@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@A@3EJ@X@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@W@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVW@@@8" to i8*), i32 4, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3W@@8" } +// CHECK: @"\01??_R13?0A@EN@M@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUM@@@8" to i8*), i32 1, i32 4, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3M@@8" } +// CHECK: @"\01??_R0?AUM@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUM@@\00" } +// CHECK: @"\01??_R3M@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 2, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([3 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2M@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2M@@8" = linkonce_odr constant [3 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@M@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EN@N@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@M@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUM@@@8" to i8*), i32 1, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3M@@8" } +// CHECK: @"\01??_R1A@?0A@EN@N@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUN@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3N@@8" } +// CHECK: @"\01??_R0?AUN@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUN@@\00" } +// CHECK: @"\01??_R3N@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2N@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2N@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@N@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@N@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUN@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3N@@8" } +// CHECK: @"\01??_R13?0A@EN@N@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUN@@@8" to i8*), i32 0, i32 4, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3N@@8" } +// CHECK: @"\01??_R1A@A@3FN@V@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVV@@@8" to i8*), i32 1, i32 0, i32 0, i32 4, i32 93, %MSRTTIClassHierarchyDescriptor* @"\01??_R3V@@8" } +// CHECK: @"\01??_R0?AVV@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AVV@@\00" } +// CHECK: @"\01??_R3V@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 2, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([3 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2V@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2V@@8" = linkonce_odr constant [3 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@V@@8", %MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@X@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@?0A@EA@V@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVV@@@8" to i8*), i32 1, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3V@@8" } +// CHECK: @"\01??_R1A@?0A@EA@X@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUX@@@8" to i8*), i32 0, i32 0, i32 -1, i32 0, i32 64, %MSRTTIClassHierarchyDescriptor* @"\01??_R3X@@8" } +// CHECK: @"\01??_R0?AUX@@@8" = linkonce_odr constant %"MSRTTITypeDescriptor\07" { i32 0, i32 0, [8 x i8] c".?AUX@@\00" } +// CHECK: @"\01??_R3X@@8" = linkonce_odr constant %MSRTTIClassHierarchyDescriptor { i32 0, i32 0, i32 1, %MSRTTIBaseClassDescriptor** getelementptr inbounds ([2 x %MSRTTIBaseClassDescriptor*]* @"\01??_R2X@@8", i32 0, i32 0) } +// CHECK: @"\01??_R2X@@8" = linkonce_odr constant [2 x %MSRTTIBaseClassDescriptor*] [%MSRTTIBaseClassDescriptor* @"\01??_R1A@?0A@EA@X@@8", %MSRTTIBaseClassDescriptor* null] +// CHECK: @"\01??_R1A@A@3EJ@X@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUX@@@8" to i8*), i32 0, i32 0, i32 0, i32 4, i32 73, %MSRTTIClassHierarchyDescriptor* @"\01??_R3X@@8" } +// CHECK: @"\01??_R17?0A@EN@M@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUM@@@8" to i8*), i32 1, i32 8, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3M@@8" } +// CHECK: @"\01??_R17?0A@EN@N@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUN@@@8" to i8*), i32 0, i32 8, i32 -1, i32 0, i32 77, %MSRTTIClassHierarchyDescriptor* @"\01??_R3N@@8" } +// CHECK: @"\01??_R1A@33FN@V@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVV@@@8" to i8*), i32 1, i32 0, i32 4, i32 4, i32 93, %MSRTTIClassHierarchyDescriptor* @"\01??_R3V@@8" } +// CHECK: @"\01??_R1A@33EJ@X@@8" = linkonce_odr constant %MSRTTIBaseClassDescriptor { i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUX@@@8" to i8*), i32 0, i32 0, i32 4, i32 4, i32 73, %MSRTTIClassHierarchyDescriptor* @"\01??_R3X@@8" } +// CHECK: @"\01??_R4Y@@6BW@@@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 8, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVY@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Y@@8" } +// CHECK: @"\01??_R4W@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 4, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVW@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3W@@8" } +// CHECK: @"\01??_R4Z@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVZ@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3Z@@8" } +// CHECK: @"\01??_R4V@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AVV@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3V@@8" } +// CHECK: @"\01??_R4X@@6B@" = linkonce_odr constant %MSRTTICompleteObjectLocator { i32 0, i32 0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUX@@@8" to i8*), %MSRTTIClassHierarchyDescriptor* @"\01??_R3X@@8" }