diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1767,8 +1767,22 @@ DC->getParent()->isTranslationUnit()) EmitFundamentalRTTIDescriptors(RD); - if (!VTable->isDeclarationForLinker()) + // Always emit type metadata on non-available_externally definitions, and on + // available_externally definitions if we are performing whole program + // devirtualization. For WPD we need the type metadata on all vtable + // definitions to ensure we associate derived classes with base classes + // defined in headers but with a strong definition only in a shared library. + if (!VTable->isDeclarationForLinker() || + CGM.getCodeGenOpts().WholeProgramVTables) { CGM.EmitVTableTypeMetadata(RD, VTable, VTLayout); + // For available_externally definitions, add the vtable to + // @llvm.compiler.used so that it isn't deleted before whole program + // analysis. + if (VTable->isDeclarationForLinker()) { + assert(CGM.getCodeGenOpts().WholeProgramVTables); + CGM.addCompilerUsedGlobal(VTable); + } + } if (VTContext.isRelativeLayout() && !VTable->isDSOLocal()) CGVT.GenerateRelativeVTableAlias(VTable, VTable->getName()); diff --git a/clang/test/CodeGenCXX/type-metadata.cpp b/clang/test/CodeGenCXX/type-metadata.cpp --- a/clang/test/CodeGenCXX/type-metadata.cpp +++ b/clang/test/CodeGenCXX/type-metadata.cpp @@ -7,6 +7,7 @@ // Tests for the whole-program-vtables feature: // RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM %s // RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM-DEFAULTVIS --check-prefix=TT-ITANIUM %s +// RUN: %clang_cc1 -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT %s // RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s // Tests for cfi + whole-program-vtables: @@ -79,6 +80,13 @@ // ITANIUM-DIAG-SAME: !type [[ALL16]] // ITANIUM-SAME: !type [[FAF16:![0-9]+]] +// ITANIUM: @_ZTVN5test31EE = external unnamed_addr constant +// ITANIUM-DEFAULTVIS: @_ZTVN5test31EE = external unnamed_addr constant +// ITANIUM-OPT: @_ZTVN5test31EE = available_externally unnamed_addr constant {{[^!]*}}, +// ITANIUM-OPT-SAME: !type [[E16:![0-9]+]], +// ITANIUM-OPT-SAME: !type [[EF16:![0-9]+]] +// ITANIUM-OPT: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast ({ [3 x i8*] }* @_ZTVN5test31EE to i8*)] + // MS: comdat($"??_7A@@6B@"), !type [[A8:![0-9]+]] // MS: comdat($"??_7B@@6B0@@"), !type [[B8:![0-9]+]] // MS: comdat($"??_7B@@6BA@@@"), !type [[A8]] @@ -253,6 +261,20 @@ } +namespace test3 { +// All virtual functions are outline, so we can assume that it will +// be generated in translation unit where foo is defined. +struct E { + virtual void foo(); +}; + +void g() { + E e; + e.foo(); +} + +} // Test9 + // ITANIUM: [[A16]] = !{i64 16, !"_ZTS1A"} // ITANIUM-DIAG: [[ALL16]] = !{i64 16, !"all-vtables"} // ITANIUM: [[AF16]] = !{i64 16, !"_ZTSM1AFvvE.virtual"} @@ -286,6 +308,9 @@ // ITANIUM: [[FAF16]] = !{i64 16, [[FAF_ID:![0-9]+]]} // ITANIUM: [[FAF_ID]] = distinct !{} +// ITANIUM-OPT: [[E16]] = !{i64 16, !"_ZTSN5test31EE"} +// ITANIUM-OPT: [[EF16]] = !{i64 16, !"_ZTSMN5test31EEFvvE.virtual"} + // MS: [[A8]] = !{i64 8, !"?AUA@@"} // MS: [[B8]] = !{i64 8, !"?AUB@@"} // MS: [[D8]] = !{i64 8, [[D_ID:![0-9]+]]}