diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index 6e1a80926f679..ca83d7a355408 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -326,6 +326,9 @@ cir::GlobalOp CIRGenVTables::generateConstructionVTable( return vtable; } +static bool shouldEmitAvailableExternallyVTable(const CIRGenModule &cgm, + const CXXRecordDecl *rd); + /// Compute the required linkage of the vtable for the given class. /// /// Note that we only call this at the end of the translation unit. @@ -395,11 +398,14 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) { case TSK_ImplicitInstantiation: return discardableODRLinkage; - case TSK_ExplicitInstantiationDeclaration: { - errorNYI(rd->getSourceRange(), - "getVTableLinkage: explicit instantiation declaration"); - return cir::GlobalLinkageKind::ExternalLinkage; - } + case TSK_ExplicitInstantiationDeclaration: + // Explicit instantiations in MSVC do not provide vtables, so we must emit + // our own. + if (getTarget().getCXXABI().isMicrosoft()) + return discardableODRLinkage; + return shouldEmitAvailableExternallyVTable(*this, rd) + ? cir::GlobalLinkageKind::AvailableExternallyLinkage + : cir::GlobalLinkageKind::ExternalLinkage; case TSK_ExplicitInstantiationDefinition: return nonDiscardableODRLinkage; diff --git a/clang/test/CIR/CodeGen/vtable-linkage-explicit-instantiation.cpp b/clang/test/CIR/CodeGen/vtable-linkage-explicit-instantiation.cpp new file mode 100644 index 0000000000000..6fc4cc4d51fbf --- /dev/null +++ b/clang/test/CIR/CodeGen/vtable-linkage-explicit-instantiation.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s + +// Test that explicit instantiation declarations don't trigger +// "getVTableLinkage: explicit instantiation declaration" errorNYI. + +template +struct Base { + virtual ~Base() {} + virtual void foo() {} + T val; +}; + +extern template class Base; + +void use(Base *p) { + p->foo(); +} + +// Verify the virtual call goes through the vtable. +// CHECK: cir.func {{.*}} @_Z3useP4BaseIiE +// CHECK: cir.vtable.get_vptr +// CHECK: cir.vtable.get_virtual_fn_addr + +// LLVM: define {{.*}} @_Z3useP4BaseIiE