[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)
Tomohiro Kashiwada via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 5 04:51:08 PST 2026
https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/168171
>From 949abf8addb865099cb92b2f58abc885144965f5 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 5 Mar 2026 21:37:35 +0900
Subject: [PATCH 1/3] pretest
---
...t_instantiation.exclude_from_dllexport.cpp | 206 ++++++++++++++++++
...t_instantiation.exclude_from_dllimport.cpp | 205 +++++++++++++++++
2 files changed, 411 insertions(+)
create mode 100644 clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
create mode 100644 clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
new file mode 100644
index 0000000000000..f417140b0301e
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,206 @@
+// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir
+//
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll
+// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll
+// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
+//
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll
+// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll
+// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
+//
+// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll
+// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll
+// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
+
+// Because --implicit-check-not doesn't work with -DAG checks, negative checks
+// are performed on another independent path.
+// UNDESIRED-MSC: $"?notToBeInstantiated@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv = comdat any
+// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any
+// UNDESIRED-MSC: $"?notToBeInstantiated@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ" = comdat any
+// UNDESIRED-GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv = comdat any
+// UNDESIRED-MSC: $"?notToBeInstantiated@?$Polymorphic at UWithExportTag@@@@QEAAXXZ" = comdat any
+// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv = comdat any
+// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$Polymorphic at UWithExportTag@@@@QEAAXXZ" = comdat any
+// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any
+
+#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
+
+struct NoAttrTag {};
+struct WithExportTag {};
+struct ImplicitTag {};
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute.
+template <class T>
+struct BasicCase {
+ void noAttrMethod() {}
+ EXCLUDE_ATTR void excludedMethod() {}
+ EXCLUDE_ATTR __declspec(dllexport) void excludedExportedMethod() {}
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+ EXCLUDE_ATTR __declspec(dllexport) void notToBeInstantiated_withExport() {}
+};
+
+/// Test that an exported explicit instantiation definition causes to export
+/// non-exclued methods (i.e., noAttrMethod) only.
+template struct __declspec(dllexport) BasicCase<WithExportTag>;
+// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE12noAttrMethodEv
+
+// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv
+
+// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv
+
+/// Test that a non-exported explicit instantiation definition instantiates
+/// non-exclued methods but not exports.
+template struct BasicCase<NoAttrTag>;
+// MSC-DAG: define weak_odr dso_local void @"?noAttrMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+// GNU-DAG: define weak_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE12noAttrMethodEv
+
+/// Test that an excluded method isn't exported even if the previous explicit
+/// instantiation definition or the method itself is exported.
+/// A never-called method `notToBeInstantiated` makes sure that an excluded
+/// method isn't instantiated unexpectedly.
+void useBasicCase() {
+ BasicCase<WithExportTag>().excludedMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv
+
+ BasicCase<WithExportTag>().excludedExportedMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv
+
+ BasicCase<NoAttrTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv
+
+ BasicCase<NoAttrTag>().excludedExportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedExportedMethodEv
+
+ BasicCase<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv
+
+ BasicCase<ImplicitTag>().excludedExportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE22excludedExportedMethodEv
+}
+
+// Test that a class-level dllexport attribute won't affect to excluded methods.
+template <class T>
+struct __declspec(dllexport) ExportWholeTemplate {
+ void noAttrMethod() {}
+ EXCLUDE_ATTR void excludedMethod() {}
+ EXCLUDE_ATTR void excludedNoinlineMethod();
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+};
+
+// MSVC and MinGW disagree on whether an inline method of a class-level exported
+// template should be exported.
+template <typename T> void ExportWholeTemplate<T>::excludedNoinlineMethod() {}
+
+template struct ExportWholeTemplate<NoAttrTag>;
+// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE12noAttrMethodEv
+
+// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv
+
+void useExportWholeTemplate() {
+ ExportWholeTemplate<NoAttrTag>().excludedMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv
+
+ ExportWholeTemplate<NoAttrTag>().excludedNoinlineMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
+
+ ExportWholeTemplate<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE14excludedMethodEv
+
+ ExportWholeTemplate<ImplicitTag>().excludedNoinlineMethod();
+ // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv
+}
+
+// Interaction with VTables.
+template <class T>
+struct Polymorphic {
+ EXCLUDE_ATTR explicit Polymorphic() = default;
+ virtual void noAttrVirtualMethod() {}
+ EXCLUDE_ATTR virtual void excludedVirtualMethod() {}
+ EXCLUDE_ATTR __declspec(dllexport) virtual void excludedExportedVirtualMethod() {}
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+ EXCLUDE_ATTR __declspec(dllexport) void notToBeInstantiated_withExport() {}
+};
+
+template struct __declspec(dllexport) Polymorphic<WithExportTag>;
+// MSC-DAG: @"??_7?$Polymorphic at UWithExportTag@@@@6B@" = dllexport unnamed_addr
+// GNU-DAG: @_ZTV11PolymorphicI13WithExportTagE = weak_odr dso_local dllexport unnamed_addr
+
+// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19noAttrVirtualMethodEv
+
+// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv
+
+// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv
+
+// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$Polymorphic at UWithExportTag@@@@QEAAXXZ"
+// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv
+
+// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$Polymorphic at UWithExportTag@@@@QEAAXXZ"
+// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv
+
+template struct Polymorphic<NoAttrTag>;
+// MSC-DAG: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
+// GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = weak_odr dso_local unnamed_addr
+
+// MSC-DAG: define weak_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE29excludedExportedVirtualMethodEv
+
+void usePolymorphic() {
+ new Polymorphic<ImplicitTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UImplicitTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE29excludedExportedVirtualMethodEv
+}
+
+/// Test that the DLL attrribute wins over the exclude attribute on a
+/// non-template context.
+struct NonTemplateClass {
+ EXCLUDE_ATTR __declspec(dllexport) void excludedExportedMethod();
+};
+
+void NonTemplateClass::excludedExportedMethod() {}
+// MSC-DAG: define dso_local dllexport void @"?excludedExportedMethod at NonTemplateClass@@QEAAXXZ"
+// GNU-DAG: define dso_local dllexport void @_ZN16NonTemplateClass22excludedExportedMethodEv
+
+/// The same, but exporting whole class.
+struct __declspec(dllexport) NonTemplateExportedClass {
+ EXCLUDE_ATTR void excludedMethod();
+};
+
+void NonTemplateExportedClass::excludedMethod() {}
+// MSC-DAG: define dso_local dllexport void @"?excludedMethod at NonTemplateExportedClass@@QEAAXXZ"
+// GNU-DAG: define dso_local dllexport void @_ZN24NonTemplateExportedClass14excludedMethodEv
diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
new file mode 100644
index 0000000000000..dd9347f27cbfc
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,205 @@
+// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir
+//
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll
+// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll
+// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
+//
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll
+// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll
+// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
+//
+// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll
+// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll
+// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
+
+// Because --implicit-check-not doesn't work with -DAG checks, negative checks
+// are performed on another independent path.
+
+#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
+
+struct NoAttrTag {};
+struct WithImportTag {};
+struct ImplicitTag {};
+
+// Test that __declspec(dllimport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute.
+template <class T>
+struct BasicCase {
+ void noAttrMethod() {}
+ EXCLUDE_ATTR void excludedMethod() {}
+ EXCLUDE_ATTR __declspec(dllimport) void excludedImportedMethod() {}
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+ EXCLUDE_ATTR __declspec(dllimport) void notToBeInstantiated_withImport() {}
+ void notToBeInstantiated_noAttr() {}
+};
+
+extern template struct __declspec(dllimport) BasicCase<WithImportTag>;
+extern template struct BasicCase<NoAttrTag>;
+
+/// Test that an excluded method isn't imported even if the previous explicit
+/// instantiation declaration or the method itself is imported.
+/// A never-called method `notToBeInstantiated` makes sure that an excluded
+/// method isn't instantiated unexpectedly.
+void useBaseCase() {
+ BasicCase<WithImportTag>().noAttrMethod();
+ // MSC-DAG: declare dllimport void @"?noAttrMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE12noAttrMethodEv
+
+ BasicCase<WithImportTag>().excludedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv
+
+ BasicCase<WithImportTag>().excludedImportedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedImportedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv
+
+ BasicCase<NoAttrTag>().noAttrMethod();
+ // MSC-DAG: declare dso_local void @"?noAttrMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dso_local void @_ZN9BasicCaseI9NoAttrTagE12noAttrMethodEv
+
+ BasicCase<NoAttrTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv
+
+ BasicCase<NoAttrTag>().excludedImportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedImportedMethodEv
+
+ BasicCase<ImplicitTag>().noAttrMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE12noAttrMethodEv
+
+ BasicCase<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv
+
+ BasicCase<ImplicitTag>().excludedImportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE22excludedImportedMethodEv
+}
+
+// Test that a class-level dllimport attribute won't affect to excluded methods.
+template <class T>
+struct __declspec(dllimport) ImportWholeTemplate {
+ void noAttrMethod() {}
+ EXCLUDE_ATTR void excludedMethod() {}
+ EXCLUDE_ATTR void excludedNoinlineMethod();
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+ void notToBeInstantiated_noAttr() {}
+};
+
+// MSVC and MinGW disagree on whether an inline method of a class-level imported
+// template should be imported.
+template <typename T> void ImportWholeTemplate<T>::excludedNoinlineMethod() {}
+
+extern template struct ImportWholeTemplate<NoAttrTag>;
+
+void useImportWholeTemplate() {
+ ImportWholeTemplate<NoAttrTag>().excludedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv
+
+ ImportWholeTemplate<NoAttrTag>().excludedNoinlineMethod();
+ // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
+
+ ImportWholeTemplate<ImplicitTag>().excludedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE14excludedMethodEv
+
+ ImportWholeTemplate<ImplicitTag>().excludedNoinlineMethod();
+ // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv
+}
+
+template <class T>
+struct Polymorphic {
+ EXCLUDE_ATTR explicit Polymorphic() {}
+ virtual void noAttrVirtualMethod() {}
+ EXCLUDE_ATTR virtual void excludedVirtualMethod() {}
+ EXCLUDE_ATTR __declspec(dllimport) virtual void excludedImportedVirtualMethod() {}
+ EXCLUDE_ATTR void notToBeInstantiated() {}
+ EXCLUDE_ATTR __declspec(dllimport) void notToBeInstantiated_withImport() {}
+ void notToBeInstantiated_noAttr() {}
+};
+
+extern template struct __declspec(dllimport) Polymorphic<WithImportTag>;
+extern template struct Polymorphic<NoAttrTag>;
+
+/// For the MSVC ABI:
+/// A call to an excluded constructor implicitly instantiates the VTable, which
+/// triggers the instantiation of all virtual methods, regardless of the exclude
+/// attribute. Therefore, the `MSC-DAG` checks are repeated four times for each
+/// specialization: once for the VTable and three times for the all three
+/// virtual methods of the class template.
+///
+/// For the Itanium ABI:
+/// An implicit instantiation declaration suppresses emitting the VTable, so
+/// virtual member functions won't be instantiated. Therefore, for `WithImportTag`
+/// and `NoAttrTag` specializations, that have an explicit instantiation
+/// declaration, only one `GNU-DAG` check to verify the VTable and three
+/// `NEGATIVE-GNU-NOT` checks to ensure the virtual methods are not emitted
+/// anywhere are placed. For the `ImplicitTag` specialization, `GNU-DAG` checks
+/// are placed four times, since the virtual methods are implicitly instantiated.
+///
+void usePolymorphic() {
+ new Polymorphic<WithImportTag>();
+ // UNDESIRED-MSC-NOT: @"??_{{.}}?$Polymorphic at UWithImportTag@@@@6B@" = unnamed_addr
+ // UNDESIRED-GNU-NOT: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr
+
+ // UNDESIRED-MSC-NOT: @"?noAttrVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv
+
+ // UNDESIRED-MSC-NOT: @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv
+
+ // UNDESIRED-MSC-NOT: @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv
+
+ new Polymorphic<NoAttrTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = external unnamed_addr
+
+ // MSC-DAG: declare dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE29excludedImportedVirtualMethodEv
+
+ new Polymorphic<ImplicitTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UImplicitTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE29excludedImportedVirtualMethodEv
+}
+
+/// Test that the DLL attrribute wins over the exclude attribute on a
+/// non-template context.
+struct NonTemplateClass {
+ EXCLUDE_ATTR __declspec(dllimport) void excludedImportedMethod();
+};
+
+struct __declspec(dllimport) NonTemplateImportedClass {
+ EXCLUDE_ATTR void excludedMethod();
+};
+
+void useNonTemplateClass() {
+ NonTemplateClass().excludedImportedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedImportedMethod at NonTemplateClass@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN16NonTemplateClass22excludedImportedMethodEv
+
+ NonTemplateImportedClass().excludedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedMethod at NonTemplateImportedClass@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN24NonTemplateImportedClass14excludedMethodEv
+}
+
>From b892bb596e6a0d9548b49c8d1026405349b618ff Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 5 Mar 2026 21:37:36 +0900
Subject: [PATCH 2/3] [Clang] Apply exclude_from_explicit_instantiation to
dllimport/dllexport
Attaching `__declspec(dllexport/dllimport)` to explicit instantiation
declaration made its whole member instantiated even if they were
`__attribute__((__exclude_from_explicit_instantation__))`.
Such members should not be instantiated nor be exported to avoid
symbol leakage or duplication.
---
clang/lib/Sema/SemaDeclCXX.cpp | 5 ++
...t_instantiation.exclude_from_dllexport.cpp | 55 +++++--------------
...t_instantiation.exclude_from_dllimport.cpp | 32 +++++------
3 files changed, 36 insertions(+), 56 deletions(-)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5837ecd6b9163..fdf3898ba52e5 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6592,6 +6592,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
// seem to be true in practice?
for (Decl *Member : Class->decls()) {
+ if ((TSK == TSK_ExplicitInstantiationDeclaration ||
+ TSK == TSK_ExplicitInstantiationDefinition) &&
+ Member->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+ continue;
+
VarDecl *VD = dyn_cast<VarDecl>(Member);
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
index f417140b0301e..7ee64a2c75b6c 100644
--- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -2,28 +2,18 @@
//
// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll
// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll
-// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
+// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
//
// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll
// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll
-// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
+// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
//
// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll
// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll
-// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
+// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
// Because --implicit-check-not doesn't work with -DAG checks, negative checks
// are performed on another independent path.
-// UNDESIRED-MSC: $"?notToBeInstantiated@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
-// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv = comdat any
-// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
-// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any
-// UNDESIRED-MSC: $"?notToBeInstantiated@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ" = comdat any
-// UNDESIRED-GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv = comdat any
-// UNDESIRED-MSC: $"?notToBeInstantiated@?$Polymorphic at UWithExportTag@@@@QEAAXXZ" = comdat any
-// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv = comdat any
-// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$Polymorphic at UWithExportTag@@@@QEAAXXZ" = comdat any
-// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any
#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
@@ -48,12 +38,6 @@ template struct __declspec(dllexport) BasicCase<WithExportTag>;
// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
// GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE12noAttrMethodEv
-// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
-// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv
-
-// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
-// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv
-
/// Test that a non-exported explicit instantiation definition instantiates
/// non-exclued methods but not exports.
template struct BasicCase<NoAttrTag>;
@@ -66,12 +50,12 @@ template struct BasicCase<NoAttrTag>;
/// method isn't instantiated unexpectedly.
void useBasicCase() {
BasicCase<WithExportTag>().excludedMethod();
- // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
- // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv
BasicCase<WithExportTag>().excludedExportedMethod();
- // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
- // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv
BasicCase<NoAttrTag>().excludedMethod();
// MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
@@ -107,17 +91,14 @@ template struct ExportWholeTemplate<NoAttrTag>;
// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
// GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE12noAttrMethodEv
-// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
-// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv
-
void useExportWholeTemplate() {
ExportWholeTemplate<NoAttrTag>().excludedMethod();
- // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
- // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv
ExportWholeTemplate<NoAttrTag>().excludedNoinlineMethod();
- // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
- // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
ExportWholeTemplate<ImplicitTag>().excludedMethod();
// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
@@ -146,17 +127,11 @@ template struct __declspec(dllexport) Polymorphic<WithExportTag>;
// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19noAttrVirtualMethodEv
-// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
-// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv
-
-// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
-// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv
-
-// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$Polymorphic at UWithExportTag@@@@QEAAXXZ"
-// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv
-// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$Polymorphic at UWithExportTag@@@@QEAAXXZ"
-// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv
template struct Polymorphic<NoAttrTag>;
// MSC-DAG: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
index dd9347f27cbfc..f6ca73d4cb847 100644
--- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -2,15 +2,15 @@
//
// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll
// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll
-// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
+// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll
//
// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll
// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll
-// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
+// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll
//
// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll
// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll
-// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
+// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll
// Because --implicit-check-not doesn't work with -DAG checks, negative checks
// are performed on another independent path.
@@ -46,12 +46,12 @@ void useBaseCase() {
// GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE12noAttrMethodEv
BasicCase<WithImportTag>().excludedMethod();
- // MSC-DAG: declare dllimport void @"?excludedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
- // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv
BasicCase<WithImportTag>().excludedImportedMethod();
- // MSC-DAG: declare dllimport void @"?excludedImportedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
- // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv
BasicCase<NoAttrTag>().noAttrMethod();
// MSC-DAG: declare dso_local void @"?noAttrMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
@@ -96,12 +96,12 @@ extern template struct ImportWholeTemplate<NoAttrTag>;
void useImportWholeTemplate() {
ImportWholeTemplate<NoAttrTag>().excludedMethod();
- // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
- // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv
ImportWholeTemplate<NoAttrTag>().excludedNoinlineMethod();
- // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
- // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv
ImportWholeTemplate<ImplicitTag>().excludedMethod();
// MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
@@ -144,16 +144,16 @@ extern template struct Polymorphic<NoAttrTag>;
///
void usePolymorphic() {
new Polymorphic<WithImportTag>();
- // UNDESIRED-MSC-NOT: @"??_{{.}}?$Polymorphic at UWithImportTag@@@@6B@" = unnamed_addr
- // UNDESIRED-GNU-NOT: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr
+ // MSC-DAG: @"??_S?$Polymorphic at UWithImportTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr
- // UNDESIRED-MSC-NOT: @"?noAttrVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv
- // UNDESIRED-MSC-NOT: @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv
- // UNDESIRED-MSC-NOT: @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv
new Polymorphic<NoAttrTag>();
>From baafdd7160e22e17bd3cf24a7c9bf32148cef4e7 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 5 Mar 2026 21:37:37 +0900
Subject: [PATCH 3/3] instantiate vtable
---
clang/lib/Sema/SemaDeclCXX.cpp | 16 ++++++++++++++--
...icit_instantiation.exclude_from_dllimport.cpp | 8 ++++----
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index fdf3898ba52e5..8173a4b53a679 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -19124,8 +19124,20 @@ bool Sema::DefineUsedVTables() {
}
}
- if (IsExplicitInstantiationDeclaration)
- DefineVTable = false;
+ if (IsExplicitInstantiationDeclaration) {
+ const bool HasExcludeFromExplicitInstantiation =
+ llvm::any_of(Class->methods(), [](CXXMethodDecl *method) {
+ // If the class has a member function declared with
+ // `__attribute__((exclude_from_explicit_instantiation))`, the
+ // explicit instantiation declaration should not suppress emitting
+ // the vtable, since the corresponding explicit instantiation
+ // definition might not emit the vtable if a triggering method is
+ // excluded.
+ return method->hasAttr<ExcludeFromExplicitInstantiationAttr>();
+ });
+ if (!HasExcludeFromExplicitInstantiation)
+ DefineVTable = false;
+ }
}
// The exception specifications for all virtual members may be needed even
diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
index f6ca73d4cb847..f2dd22f53ac08 100644
--- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -150,10 +150,10 @@ void usePolymorphic() {
// MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv
- // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv
- // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv
new Polymorphic<NoAttrTag>();
@@ -163,10 +163,10 @@ void usePolymorphic() {
// MSC-DAG: declare dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv
- // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv
- // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
// NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE29excludedImportedVirtualMethodEv
new Polymorphic<ImplicitTag>();
More information about the cfe-commits
mailing list