From: Richard Smith Date: Sat, 16 Feb 2013 00:51:21 +0000 (+0000) Subject: Emit vtables for an extern template class as available_externally, not as X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b4127a28a6dd81852469d05c611a487beb233784;p=clang Emit vtables for an extern template class as available_externally, not as linkonce_odr. Emit construction vtables as internal in this case, since the ABI does not guarantee that they will be availble externally. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175330 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 6d402197e0..0c5d72fd8b 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -686,6 +686,14 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, llvm::ArrayType *ArrayType = llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents()); + // Construction vtable symbols are not part of the Itanium ABI, so we cannot + // guarantee that they actually will be available externally. Instead, when + // emitting an available_externally VTT, we provide references to an internal + // linkage construction vtable. The ABI only requires complete-object vtables + // to be the same for all instances of a type, not construction vtables. + if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) + Linkage = llvm::GlobalVariable::InternalLinkage; + // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage); @@ -750,11 +758,8 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { llvm::Function::InternalLinkage; case TSK_ExplicitInstantiationDeclaration: - // FIXME: Use available_externally linkage. However, this currently - // breaks LLVM's build due to undefined symbols. - // return llvm::GlobalVariable::AvailableExternallyLinkage; return !Context.getLangOpts().AppleKext ? - llvm::GlobalVariable::LinkOnceODRLinkage : + llvm::GlobalVariable::AvailableExternallyLinkage : llvm::Function::InternalLinkage; } } @@ -771,10 +776,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { return llvm::GlobalVariable::LinkOnceODRLinkage; case TSK_ExplicitInstantiationDeclaration: - // FIXME: Use available_externally linkage. However, this currently - // breaks LLVM's build due to undefined symbols. - // return llvm::GlobalVariable::AvailableExternallyLinkage; - return llvm::GlobalVariable::LinkOnceODRLinkage; + return llvm::GlobalVariable::AvailableExternallyLinkage; case TSK_ExplicitInstantiationDefinition: return llvm::GlobalVariable::WeakODRLinkage; diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp index 4633a3fe95..b945e569af 100644 --- a/test/CodeGenCXX/vtable-linkage.cpp +++ b/test/CodeGenCXX/vtable-linkage.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -disable-llvm-optzns -O3 -emit-llvm -o %t.opt // RUN: FileCheck --check-prefix=CHECK-1 %s < %t // RUN: FileCheck --check-prefix=CHECK-2 %s < %t // RUN: FileCheck --check-prefix=CHECK-2-HIDDEN %s < %t.hidden @@ -12,7 +13,9 @@ // RUN: FileCheck --check-prefix=CHECK-7 %s < %t // RUN: FileCheck --check-prefix=CHECK-8 %s < %t // RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9-OPT %s < %t.opt // RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10-OPT %s < %t.opt // RUN: FileCheck --check-prefix=CHECK-11 %s < %t // RUN: FileCheck --check-prefix=CHECK-12 %s < %t // RUN: FileCheck --check-prefix=CHECK-13 %s < %t @@ -160,11 +163,13 @@ void use_F() { // F is an explicit template instantiation declaration without a // key function, so its vtable should have external linkage. // CHECK-9: @_ZTV1FIiE = external unnamed_addr constant +// CHECK-9-OPT: @_ZTV1FIiE = available_externally unnamed_addr constant // E is an explicit template instantiation declaration. It has a // key function that is not instantiated, so we should only reference // its vtable, not define it. // CHECK-10: @_ZTV1EIiE = external unnamed_addr constant +// CHECK-10-OPT: @_ZTV1EIiE = available_externally unnamed_addr constant // The anonymous struct for e has no linkage, so the vtable should have // internal linkage. @@ -214,3 +219,24 @@ public: void use_H() { H h; } + +// RUN: FileCheck --check-prefix=CHECK-I %s < %t +// RUN: FileCheck --check-prefix=CHECK-I-OPT %s < %t.opt + +// I has an explicit instantiation declaration and needs a VTT and +// construction vtables. We emit the VTT available_externally, but point it at +// internal construction vtables because there is no way to form a reference to +// the real construction vtables. + +// CHECK-I: @_ZTV1IIiE = external unnamed_addr constant +// CHECK-I: @_ZTT1IIiE = external unnamed_addr constant +// CHECK-I-NOT: @_ZTC1IIiE +// +// CHECK-I-OPT: @_ZTV1IIiE = available_externally unnamed_addr constant +// CHECK-I-OPT: @_ZTT1IIiE = available_externally unnamed_addr constant {{.*}} @_ZTC1IIiE0_6VBase2 +// CHECK-I-OPT: @_ZTC1IIiE0_6VBase2 = internal unnamed_addr constant +struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {}; +template +struct I : VBase2 {}; +extern template struct I; +I i;