Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -9793,6 +9793,12 @@ return !D->getDeclContext()->isDependentContext(); else if (isa(D)) return true; + else if (auto *RD = dyn_cast(D)) + // An explicit instantiation of a dynamic class emits the vtable and + // type_info objects, so must be emitted. + return RD->hasDefinition() && RD->isDynamicClass() && + RD->getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDefinition; else return false; @@ -9842,8 +9848,11 @@ if (const auto *FD = dyn_cast(D)) { // Multiversioned functions always have to be emitted, because they are used // by the resolver. + // FIXME: This doesn't appear to be correct. Multiversioned functions should + // only be emitted if the resolver is emitted. if (FD->isMultiVersion()) return true; + // Forward declarations aren't required. if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); @@ -9852,19 +9861,6 @@ if (FD->hasAttr() || FD->hasAttr()) return true; - // The key function for a class is required. This rule only comes - // into play when inline functions can be key functions, though. - if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { - if (const auto *MD = dyn_cast(FD)) { - const CXXRecordDecl *RD = MD->getParent(); - if (MD->isOutOfLine() && RD->isDynamicClass()) { - const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD); - if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) - return true; - } - } - } - GVALinkage Linkage = GetGVALinkageForFunction(FD); // static, static inline, always_inline, and extern inline functions can Index: lib/AST/RecordLayoutBuilder.cpp =================================================================== --- lib/AST/RecordLayoutBuilder.cpp +++ lib/AST/RecordLayoutBuilder.cpp @@ -3053,7 +3053,7 @@ } const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { - if (!getTargetInfo().getCXXABI().hasKeyFunctions()) + if (!getTargetInfo().getCXXABI().hasKeyFunctions() || !RD->isDynamicClass()) return nullptr; assert(RD->getDefinition() && "Cannot get key function for forward decl!"); Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp +++ lib/CodeGen/CGCXX.cpp @@ -206,12 +206,6 @@ llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD, StructorType Type) { - const CGFunctionInfo &FnInfo = - getTypes().arrangeCXXStructorDeclaration(MD, Type); - auto *Fn = cast( - getAddrOfCXXStructor(MD, Type, &FnInfo, /*FnType=*/nullptr, - /*DontDefer=*/true, ForDefinition)); - GlobalDecl GD; if (const auto *DD = dyn_cast(MD)) { GD = GlobalDecl(DD, toCXXDtorType(Type)); @@ -220,12 +214,7 @@ GD = GlobalDecl(CD, toCXXCtorType(Type)); } - setFunctionLinkage(GD, Fn); - - CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo); - setNonAliasAttributes(GD, Fn); - SetLLVMFunctionAttributesForDefinition(MD, Fn); - return Fn; + return cast(EmitGlobalFunctionDefinition(GD)); } llvm::Constant *CodeGenModule::getAddrOfCXXStructor( Index: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -420,6 +420,9 @@ virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) = 0; + /// Ensure that all vtables for the given class are emitted. + virtual void emitVTables(const CXXRecordDecl *RD) = 0; + /// Build a virtual function pointer in the ABI-specific way. virtual CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, Address This, Index: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ lib/CodeGen/CGVTables.cpp @@ -876,14 +876,14 @@ llvm_unreachable("Invalid TemplateSpecializationKind!"); } -/// This is a callback from Sema to tell us that a particular vtable is -/// required to be emitted in this translation unit. +/// This is called when a particular vtable is required to be emitted in this +/// translation unit. /// /// This is only called for vtables that _must_ be emitted (mainly due to key /// functions). For weak vtables, CodeGen tracks when they are needed and /// emits them as-needed. -void CodeGenModule::EmitVTable(CXXRecordDecl *theClass) { - VTables.GenerateClassData(theClass); +void CodeGenModule::EmitVTable(const CXXRecordDecl *theClass) { + getCXXABI().emitVTables(theClass); } void @@ -955,21 +955,15 @@ /// vtables, and that we are now at the end of the translation unit, /// decide whether we should emit them. void CodeGenModule::EmitDeferredVTables() { -#ifndef NDEBUG - // Remember the size of DeferredVTables, because we're going to assume - // that this entire operation doesn't modify it. - size_t savedSize = DeferredVTables.size(); -#endif - - for (const CXXRecordDecl *RD : DeferredVTables) - if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD)) - VTables.GenerateClassData(RD); - else if (shouldOpportunisticallyEmitVTables()) - OpportunisticVTables.push_back(RD); - - assert(savedSize == DeferredVTables.size() && - "deferred extra vtables during vtable emission?"); - DeferredVTables.clear(); + while (!DeferredVTables.empty()) { + auto WorkList = std::move(DeferredVTables); + DeferredVTables.clear(); + for (const CXXRecordDecl *RD : WorkList) + if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD)) + VTables.GenerateClassData(RD); + else if (shouldOpportunisticallyEmitVTables()) + OpportunisticVTables.push_back(RD); + } } bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) { Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -321,10 +321,6 @@ Gen->AssignInheritanceModel(RD); } - void HandleVTable(CXXRecordDecl *RD) override { - Gen->HandleVTable(RD); - } - static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, unsigned LocCookie) { SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1110,7 +1110,7 @@ void EmitTentativeDefinition(const VarDecl *D); - void EmitVTable(CXXRecordDecl *Class); + void EmitVTable(const CXXRecordDecl *Class); void RefreshTypeCacheForClass(const CXXRecordDecl *Class); @@ -1312,7 +1312,8 @@ void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr); - void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); + llvm::GlobalValue * + EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV = nullptr); void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -2455,7 +2455,8 @@ if (FD->isMultiVersion()) return EmitMultiVersionFunctionDefinition(GD, GV); - return EmitGlobalFunctionDefinition(GD, GV); + EmitGlobalFunctionDefinition(GD, GV); + return; } if (const auto *VD = dyn_cast(D)) @@ -3940,7 +3941,7 @@ EmitTopLevelDecl(VD); } -void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, +llvm::GlobalValue *CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); @@ -3956,7 +3957,7 @@ // Already emitted. if (!GV->isDeclaration()) - return; + return GV; // We need to set linkage and visibility on the function before // generating code for it because various parts of IR generation @@ -3973,7 +3974,7 @@ maybeSetTrivialComdat(*D, *Fn); - CodeGenFunction(*this).GenerateCode(D, Fn, FI); + CodeGenFunction(*this).GenerateCode(GD, Fn, FI); setNonAliasAttributes(GD, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); @@ -3984,6 +3985,16 @@ AddGlobalDtor(Fn, DA->getPriority()); if (D->hasAttr()) AddGlobalAnnotations(D, Fn); + + // If we emit a key function, also emit the vtable. + if (auto *MD = dyn_cast(D)) { + // FIXME: There's no reason to do this if the key function is inline. + // Formally, the ABI requires it, but the difference is not observable. + if (declaresSameEntity(Context.getCurrentKeyFunction(MD->getParent()), MD)) + EmitVTable(MD->getParent()); + } + + return Fn; } void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { @@ -4797,14 +4808,22 @@ case Decl::Namespace: EmitDeclContext(cast(D)); break; - case Decl::ClassTemplateSpecialization: { - const auto *Spec = cast(D); - if (DebugInfo && - Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition && - Spec->hasDefinition()) - DebugInfo->completeTemplateDefinition(*Spec); - } LLVM_FALLTHROUGH; - case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::CXXRecord: { + auto *RD = cast(D); + // If this class was explicitly instantiated, emit the accompanying data. + if (RD->getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDefinition && + RD->hasDefinition()) { + if (DebugInfo) { + // FIXME: This should almost certainly apply to explicitly instantiated + // member classes of class templates too. + if (auto *CTSD = dyn_cast(RD)) + DebugInfo->completeTemplateDefinition(*CTSD); + } + if (RD->isDynamicClass()) + EmitVTable(RD); + } if (DebugInfo) { if (auto *ES = D->getASTContext().getExternalSource()) if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never) @@ -4815,6 +4834,7 @@ if (isa(I) || isa(I)) EmitTopLevelDecl(I); break; + } // No code generation needed. case Decl::UsingShadow: case Decl::ClassTemplate: Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -274,6 +274,10 @@ llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; + void emitVTables(const CXXRecordDecl *RD) override { + (void) getAddrOfVTable(RD, CharUnits()); + } + CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, Address This, llvm::Type *Ty, SourceLocation Loc) override; Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -292,6 +292,8 @@ llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; + void emitVTables(const CXXRecordDecl *RD) override; + CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, Address This, llvm::Type *Ty, SourceLocation Loc) override; @@ -1710,23 +1712,7 @@ MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext(); const VPtrInfoVector &VFPtrs = VTContext.getVFPtrOffsets(RD); - if (DeferredVFTables.insert(RD).second) { - // We haven't processed this record type before. - // Queue up this vtable for possible deferred emission. - CGM.addDeferredVTable(RD); - -#ifndef NDEBUG - // Create all the vftables at once in order to make sure each vftable has - // a unique mangled name. - llvm::StringSet<> ObservedMangledNames; - for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { - SmallString<256> Name; - mangleVFTableName(getMangleContext(), RD, *VFPtrs[J], Name); - if (!ObservedMangledNames.insert(Name.str()).second) - llvm_unreachable("Already saw this mangling before?"); - } -#endif - } + emitVTables(RD); const std::unique_ptr *VFPtrI = std::find_if( VFPtrs.begin(), VFPtrs.end(), [&](const std::unique_ptr& VPI) { @@ -1829,6 +1815,29 @@ return VTable; } +void MicrosoftCXXABI::emitVTables(const CXXRecordDecl *RD) { + if (DeferredVFTables.insert(RD).second) { + // We haven't processed this record type before. + // Queue up this vtable for possible deferred emission. + CGM.addDeferredVTable(RD); + +#ifndef NDEBUG + MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext(); + const VPtrInfoVector &VFPtrs = VTContext.getVFPtrOffsets(RD); + + // Create all the vftables at once in order to make sure each vftable has + // a unique mangled name. + llvm::StringSet<> ObservedMangledNames; + for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { + SmallString<256> Name; + mangleVFTableName(getMangleContext(), RD, *VFPtrs[J], Name); + assert(ObservedMangledNames.insert(Name.str()).second && + "Already saw this mangling before?"); + } +#endif + } +} + CGCallee MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, Address This, Index: lib/CodeGen/ModuleBuilder.cpp =================================================================== --- lib/CodeGen/ModuleBuilder.cpp +++ lib/CodeGen/ModuleBuilder.cpp @@ -276,13 +276,6 @@ Builder->EmitTentativeDefinition(D); } - - void HandleVTable(CXXRecordDecl *RD) override { - if (Diags.hasErrorOccurred()) - return; - - Builder->EmitVTable(RD); - } }; } Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -2771,6 +2771,10 @@ return false; } + if (auto *ES = D->getASTContext().getExternalSource()) + if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never) + return true; + if (isa(D) || isa(D) || isa(D) || @@ -2786,10 +2790,9 @@ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Var)); if (const auto *Func = dyn_cast(D)) return Func->doesThisDeclarationHaveABody() || HasBody; - - if (auto *ES = D->getASTContext().getExternalSource()) - if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never) - return true; + if (const auto *RD = dyn_cast(D)) + return RD->getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDefinition; return false; } Index: test/CodeGenCXX/aarch64-cxxabi.cpp =================================================================== --- test/CodeGenCXX/aarch64-cxxabi.cpp +++ test/CodeGenCXX/aarch64-cxxabi.cpp @@ -19,13 +19,37 @@ // CHECK: @_ZTV16CheckKeyFunction = struct CheckKeyFunction { virtual void foo(); + void bar(); }; // This is not inline when CheckKeyFunction is completed, so -// CheckKeyFunction::foo is the key function. VTables should be emitted. +// CheckKeyFunction::foo is the key function. VTables should be emitted +// if CheckKeyFunction::foo is emitted. inline void CheckKeyFunction::foo() { } +void CheckKeyFunction::bar() { + // Explicit use triggers emission of foo, which triggers emission of vtable. + CheckKeyFunction::foo(); +} + +// CHECK-NOT: @_ZTV22CheckKeyFunctionUnused = +struct CheckKeyFunctionUnused { + virtual void foo(); +}; +inline void CheckKeyFunctionUnused::foo() { +} + +// CHECK: @_ZTV14CheckVTableUse = +// Check that using the vtable is enough to trigger emission of the key +// function and thus the vtable. +struct CheckVTableUse { + virtual void foo(); +}; +inline void CheckVTableUse::foo() { +} +void *useVTable() { return new CheckVTableUse; } + //////////////////////////////////////////////////////////////////////////////// // Guard variables only specify and use the low bit to determine status, rather Index: test/CodeGenCXX/key-function-vtable.cpp =================================================================== --- test/CodeGenCXX/key-function-vtable.cpp +++ test/CodeGenCXX/key-function-vtable.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s --implicit-check-not=@_ZTV5testc +// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s --implicit-check-not=@_ZTV5testc // Simple key function test struct testa { virtual void a(); }; @@ -10,6 +10,7 @@ testb *testbvar = new testb; // Key function with out-of-line inline definition +// Key function is not emitted, so vtable is also not emitted. struct testc { virtual void a(); }; inline void testc::a() {} @@ -34,6 +35,18 @@ void testg::a() {} testg *testgvar = new testg; +// Key function with out-of-line inline definition +// Key function is emitted, so vtable is emitted. +struct testh { virtual void a(); void b(); }; +inline void testh::a() {} +void testh::b() { testh::a(); } + +// Key function with out-of-line inline definition +// VTable is used, so is emitted. +struct testi { virtual void a(); }; +inline void testi::a() {} +void use_i() { testi ti; } + struct X0 { virtual ~X0(); }; struct X1 : X0 { virtual void f(); @@ -45,7 +58,8 @@ // CHECK-DAG: @_ZTV2X1 = linkonce_odr unnamed_addr constant // CHECK-DAG: @_ZTV5testa = unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null -// CHECK-DAG: @_ZTV5testc = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null // CHECK-DAG: @_ZTV5testb = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null // CHECK-DAG: @_ZTV5teste = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null // CHECK-DAG: @_ZTVN12_GLOBAL__N_15testgE = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null +// CHECK-DAG: @_ZTV5testh = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null +// CHECK-DAG: @_ZTV5testi = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null Index: test/CodeGenCXX/rtti-linkage.cpp =================================================================== --- test/CodeGenCXX/rtti-linkage.cpp +++ test/CodeGenCXX/rtti-linkage.cpp @@ -115,6 +115,7 @@ }; inline void F::f() { } +void use_F_key_function(F &f) { f.F::f(); } const D getD(); const std::type_info &t2() { Index: test/CodeGenCXX/type_visibility.cpp =================================================================== --- test/CodeGenCXX/type_visibility.cpp +++ test/CodeGenCXX/type_visibility.cpp @@ -27,13 +27,13 @@ template struct B; // FUNS-LABEL: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant - // VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant - // VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant + // VARS-DAG: @_ZTSN5temp01BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTIN5temp01BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant - // VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden constant } namespace temp1 { @@ -44,13 +44,13 @@ template struct B; // FUNS-LABEL: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant - // VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant - // VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant + // VARS-DAG: @_ZTSN5temp11BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTIN5temp11BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant - // VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr constant + // VARS-HIDDEN-DAG: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5temp11BINS_1AEEE = weak_odr constant + // VARS-HIDDEN-DAG: @_ZTIN5temp11BINS_1AEEE = weak_odr constant } namespace temp2 { @@ -61,13 +61,13 @@ template struct B; // FUNS-LABEL: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant - // VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant - // VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant + // VARS-DAG: @_ZTSN5temp21BINS_1AEEE = weak_odr constant + // VARS-DAG: @_ZTIN5temp21BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant - // VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden constant } namespace temp3 { @@ -78,13 +78,13 @@ template struct B; // FUNS-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant - // VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS-DAG: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-DAG: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS-DAG: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant - // VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant } namespace temp4 { @@ -95,13 +95,13 @@ template struct B; // FUNS-LABEL: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant - // VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS-DAG: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-DAG: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS-DAG: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant - // VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant } namespace type0 { @@ -111,13 +111,13 @@ void A::foo() {} // FUNS-LABEL: define void @_ZN5type01A3fooEv( - // VARS: @_ZTVN5type01AE = unnamed_addr constant - // VARS: @_ZTSN5type01AE = constant - // VARS: @_ZTIN5type01AE = constant + // VARS-DAG: @_ZTVN5type01AE = unnamed_addr constant + // VARS-DAG: @_ZTSN5type01AE = constant + // VARS-DAG: @_ZTIN5type01AE = constant // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type01A3fooEv( - // VARS-HIDDEN: @_ZTVN5type01AE = unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5type01AE = constant - // VARS-HIDDEN: @_ZTIN5type01AE = constant + // VARS-HIDDEN-DAG: @_ZTVN5type01AE = unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5type01AE = constant + // VARS-HIDDEN-DAG: @_ZTIN5type01AE = constant } namespace type1 { @@ -127,13 +127,13 @@ void A::foo() {} // FUNS-LABEL: define hidden void @_ZN5type11A3fooEv( - // VARS: @_ZTVN5type11AE = unnamed_addr constant - // VARS: @_ZTSN5type11AE = constant - // VARS: @_ZTIN5type11AE = constant + // VARS-DAG: @_ZTVN5type11AE = unnamed_addr constant + // VARS-DAG: @_ZTSN5type11AE = constant + // VARS-DAG: @_ZTIN5type11AE = constant // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type11A3fooEv( - // VARS-HIDDEN: @_ZTVN5type11AE = unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5type11AE = constant - // VARS-HIDDEN: @_ZTIN5type11AE = constant + // VARS-HIDDEN-DAG: @_ZTVN5type11AE = unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5type11AE = constant + // VARS-HIDDEN-DAG: @_ZTIN5type11AE = constant } namespace type2 { @@ -143,13 +143,13 @@ void A::foo() {} // FUNS-LABEL: define void @_ZN5type21A3fooEv( - // VARS: @_ZTVN5type21AE = hidden unnamed_addr constant - // VARS: @_ZTSN5type21AE = hidden constant - // VARS: @_ZTIN5type21AE = hidden constant + // VARS-DAG: @_ZTVN5type21AE = hidden unnamed_addr constant + // VARS-DAG: @_ZTSN5type21AE = hidden constant + // VARS-DAG: @_ZTIN5type21AE = hidden constant // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type21A3fooEv( - // VARS-HIDDEN: @_ZTVN5type21AE = hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5type21AE = hidden constant - // VARS-HIDDEN: @_ZTIN5type21AE = hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5type21AE = hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5type21AE = hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5type21AE = hidden constant } namespace type3 { @@ -159,12 +159,12 @@ void A::foo() {} // FUNS-LABEL: define void @_ZN5type31A3fooEv( - // VARS: @_ZTVN5type31AE = hidden unnamed_addr constant - // VARS: @_ZTSN5type31AE = hidden constant - // VARS: @_ZTIN5type31AE = hidden constant + // VARS-DAG: @_ZTVN5type31AE = hidden unnamed_addr constant + // VARS-DAG: @_ZTSN5type31AE = hidden constant + // VARS-DAG: @_ZTIN5type31AE = hidden constant // FUNS-HIDDEN-LABEL: define void @_ZN5type31A3fooEv( - // VARS-HIDDEN: @_ZTVN5type31AE = hidden unnamed_addr constant - // VARS-HIDDEN: @_ZTSN5type31AE = hidden constant - // VARS-HIDDEN: @_ZTIN5type31AE = hidden constant + // VARS-HIDDEN-DAG: @_ZTVN5type31AE = hidden unnamed_addr constant + // VARS-HIDDEN-DAG: @_ZTSN5type31AE = hidden constant + // VARS-HIDDEN-DAG: @_ZTIN5type31AE = hidden constant } Index: test/CodeGenCXX/visibility.cpp =================================================================== --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -101,6 +101,25 @@ // CHECK-HIDDEN: _ZN6test481yE = hidden global } +namespace test27 { + template + class C { + class DEFAULT D { + void f(); + }; + }; + + template<> + class C::D { + virtual void g(); + }; + + void C::D::g() { + } + // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant + // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant +} + // CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10 // CHECK: @_ZN5Test71aE = hidden global // CHECK: @_ZN5Test71bE = global @@ -119,25 +138,6 @@ // CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8] // CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8] -namespace test27 { - template - class C { - class DEFAULT D { - void f(); - }; - }; - - template<> - class C::D { - virtual void g(); - }; - - void C::D::g() { - } - // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant - // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant -} - // CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant // CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant Index: test/CodeGenCXX/vtt-layout.cpp =================================================================== --- test/CodeGenCXX/vtt-layout.cpp +++ test/CodeGenCXX/vtt-layout.cpp @@ -78,12 +78,12 @@ } } -// CHECK: @_ZTTN5Test11BE = unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTVN5Test11BE, i32 0, inrange i32 0, i32 3) to i8*)] -// CHECK: @_ZTVN5Test51AE = unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test51AE to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void (%"struct.Test5::A"*)* @_ZN5Test51A6anchorEv to i8*)] } -// CHECK: @_ZTVN5Test61AE = unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test61AE to i8*), i8* bitcast (void ()* @__cxa_deleted_virtual to i8*), i8* bitcast (void (%"struct.Test6::A"*)* @_ZN5Test61A6anchorEv to i8*)] } -// CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4) to i8*)] -// CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr constant [13 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 0, i32 5) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 1, i32 3) to i8*)] -// CHECK: @_ZTVN5Test41DE = linkonce_odr unnamed_addr constant { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] } { [6 x i8*] [i8* inttoptr (i64 72 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 56 to i8*), i8* inttoptr (i64 40 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)], [8 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 56 to i8*), i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*), i8* bitcast (void (%"class.Test4::V3"*)* @_ZN5Test42V31gEv to i8*)], [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -40 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)], [4 x i8*] [i8* null, i8* inttoptr (i64 -56 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*), i8* bitcast (void (%"class.Test4::A2"*)* @_ZN5Test42A21fEv to i8*)], [4 x i8*] [i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -32 to i8*), i8* inttoptr (i64 -72 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)] } -// CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr constant [19 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 1, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 4, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 2, i32 3) to i8*)] +// CHECK-DAG: @_ZTTN5Test11BE = unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTVN5Test11BE, i32 0, inrange i32 0, i32 3) to i8*)] +// CHECK-DAG: @_ZTVN5Test51AE = unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test51AE to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void (%"struct.Test5::A"*)* @_ZN5Test51A6anchorEv to i8*)] } +// CHECK-DAG: @_ZTVN5Test61AE = unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test61AE to i8*), i8* bitcast (void ()* @__cxa_deleted_virtual to i8*), i8* bitcast (void (%"struct.Test6::A"*)* @_ZN5Test61A6anchorEv to i8*)] } +// CHECK-DAG: @_ZTTN5Test21CE = linkonce_odr unnamed_addr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4) to i8*)] +// CHECK-DAG: @_ZTTN5Test31DE = linkonce_odr unnamed_addr constant [13 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 0, i32 5) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [7 x i8*], [3 x i8*], [4 x i8*] }, { [7 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }, { [5 x i8*], [7 x i8*], [4 x i8*], [3 x i8*] }* @_ZTVN5Test31DE, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 1, i32 3) to i8*)] +// CHECK-DAG: @_ZTVN5Test41DE = linkonce_odr unnamed_addr constant { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] } { [6 x i8*] [i8* inttoptr (i64 72 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 56 to i8*), i8* inttoptr (i64 40 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)], [8 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 56 to i8*), i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*), i8* bitcast (void (%"class.Test4::V3"*)* @_ZN5Test42V31gEv to i8*)], [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -40 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)], [4 x i8*] [i8* null, i8* inttoptr (i64 -56 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*), i8* bitcast (void (%"class.Test4::A2"*)* @_ZN5Test42A21fEv to i8*)], [4 x i8*] [i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -32 to i8*), i8* inttoptr (i64 -72 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTIN5Test41DE to i8*)] } +// CHECK-DAG: @_ZTTN5Test41DE = linkonce_odr unnamed_addr constant [19 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 0, i32 6) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 1, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }, { [8 x i8*], [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 2, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 3, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }, { [6 x i8*], [8 x i8*], [3 x i8*], [4 x i8*], [4 x i8*] }* @_ZTVN5Test41DE, i32 0, inrange i32 4, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [4 x i8*] }, { [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 1, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*], [3 x i8*], [4 x i8*] }, { [4 x i8*], [3 x i8*], [4 x i8*] }* @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 2, i32 3) to i8*)] // CHECK: declare void @__cxa_pure_virtual() unnamed_addr // CHECK: declare void @__cxa_deleted_virtual() unnamed_addr