[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

Tomohiro Kashiwada via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 21 04:33:08 PST 2026


https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 01/20] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++++++++++++++++++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++++++++++++++
 2 files changed, 114 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..6b1bd83f6d69b
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
+
+template <class T>
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template <class T> void C<T>::to_be_exported() noexcept {}
+template <class T> void C<T>::to_be_exported_explicitly() noexcept {}
+template <class T> void C<T>::not_to_be_exported() noexcept {}
+template <class T> void C<T>::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C at H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C<int>;
+
+void use() {
+  C<int> c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void @_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void @"?not_to_be_instantiated@?$C at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void @_ZN1CIiE22not_to_be_instantiatedEv
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..adc420f37bbc6
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllimport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as dllimport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
+
+template <class T>
+struct C {
+  // This will be instantiated explicitly as an imported function because it
+  // inherits dllimport from the class instantiation.
+  void to_be_imported() noexcept;
+
+  // Per-member dllimport in explicitly dllimport-ed template instantiation is not allowed.
+  //EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an imported function unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template <class T> void C<T>::to_be_imported() noexcept {}
+template <class T> void C<T>::not_to_be_imported() noexcept {}
+template <class T> void C<T>::not_to_be_instantiated() noexcept {}
+
+extern template struct __declspec(dllimport) C<int>;
+
+void use() {
+  C<int> c;
+
+  // MSC: call void @"?to_be_imported@?$C at H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE14to_be_importedEv
+  c.to_be_imported();
+
+  //c.to_be_imported_explicitly();
+
+  // MSC: call void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_importedEv
+  c.not_to_be_imported(); // implicitly instantiated here
+};
+
+// MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv
+
+// MSC: declare dllimport void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1CIiE18not_to_be_importedEv

>From 1e558daf82c6750b14b6ea273175d29279cce450 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:25:24 +0900
Subject: [PATCH 02/20] [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 | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index aa36a79142e52..fe732a1328fab 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6551,6 +6551,8 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
     return;
   }
 
+  TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
+
   if (Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
       !ClassAttr->isInherited()) {
     // Diagnose dll attributes on members of class with dll attribute.
@@ -6561,6 +6563,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
       if (!MemberAttr || MemberAttr->isInherited() || Member->isInvalidDecl())
         continue;
 
+      if ((TSK == TSK_ExplicitInstantiationDeclaration ||
+           TSK == TSK_ExplicitInstantiationDefinition) &&
+          Member->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+        continue;
+
       Diag(MemberAttr->getLocation(),
              diag::err_attribute_dll_member_of_dll_class)
           << MemberAttr << ClassAttr;
@@ -6583,8 +6590,6 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
       !ClassExported &&
       cast<DLLImportAttr>(ClassAttr)->wasPropagatedToBaseTemplate();
 
-  TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
-
   // Ignore explicit dllexport on explicit class template instantiation
   // declarations, except in MinGW mode.
   if (ClassExported && !ClassAttr->isInherited() &&
@@ -6601,6 +6606,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);
 

>From d7e93e8c139252f102bd78fda4a3ab252bf93ab2 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:25:24 +0900
Subject: [PATCH 03/20] update test

---
 ...t_instantiation.exclude_from_dllexport.cpp | 11 +++-------
 ...t_instantiation.exclude_from_dllimport.cpp | 20 +++++++++++++------
 2 files changed, 17 insertions(+), 14 deletions(-)

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 6b1bd83f6d69b..0a94bd4b1f6b6 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
@@ -17,7 +17,7 @@ struct C {
   // marked as dllexport explicitly.
   EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly() noexcept;
 
-  // This will be instantiated implicitly as an exported function unintentionally.
+  // This will be instantiated implicitly but won't be exported.
   EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
 
   // This won't be instantiated.
@@ -32,11 +32,9 @@ template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 // MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?not_to_be_instantiated@?$C at H@@QEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
 // GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
-// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
 
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
@@ -57,8 +55,5 @@ void use() {
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE25to_be_exported_explicitlyEv
 
-// MSC: define weak_odr dso_local dllexport void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport void @_ZN1CIiE18not_to_be_exportedEv
-
-// MSC: define weak_odr dso_local dllexport void @"?not_to_be_instantiated@?$C at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport void @_ZN1CIiE22not_to_be_instantiatedEv
+// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_exportedEv
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 adc420f37bbc6..b070259c2f048 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
@@ -13,10 +13,11 @@ struct C {
   // inherits dllimport from the class instantiation.
   void to_be_imported() noexcept;
 
-  // Per-member dllimport in explicitly dllimport-ed template instantiation is not allowed.
-  //EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly() noexcept;
+  // This will be instantiated implicitly as an imported function because it is
+  // marked as dllimport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly() noexcept;
 
-  // This will be instantiated implicitly as an imported function unintentionally.
+  // This will be instantiated implicitly but won't be imported.
   EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported() noexcept;
 
   // This won't be instantiated.
@@ -27,6 +28,8 @@ template <class T> void C<T>::to_be_imported() noexcept {}
 template <class T> void C<T>::not_to_be_imported() noexcept {}
 template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 
+// MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
 extern template struct __declspec(dllimport) C<int>;
 
 void use() {
@@ -36,7 +39,9 @@ void use() {
   // GNU: call void @_ZN1CIiE14to_be_importedEv
   c.to_be_imported();
 
-  //c.to_be_imported_explicitly();
+  // MSC: call void @"?to_be_imported_explicitly@?$C at H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_imported_explicitlyEv
+  c.to_be_imported_explicitly(); // implicitly instantiated here
 
   // MSC: call void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
   // GNU: call void @_ZN1CIiE18not_to_be_importedEv
@@ -46,5 +51,8 @@ void use() {
 // MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
 // GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv
 
-// MSC: declare dllimport void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN1CIiE18not_to_be_importedEv
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$C at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1CIiE25to_be_imported_explicitlyEv
+
+// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv

>From 94d7cf7933a73410548dc787baf6d9eac5b0d60f Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sun, 30 Nov 2025 10:03:12 +0900
Subject: [PATCH 04/20] add --implicit-check-not=dll{{in|ex}}port

---
 ...it_instantiation.exclude_from_dllexport.cpp | 18 ++++++++++++++----
 ...it_instantiation.exclude_from_dllimport.cpp | 16 ++++++++++++----
 2 files changed, 26 insertions(+), 8 deletions(-)

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 0a94bd4b1f6b6..a2d8e37acb626 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
@@ -1,10 +1,18 @@
-// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
-// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
-// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport
 
 // Test that __declspec(dllexport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllexport explicitly.
 
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
 #define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
@@ -36,7 +44,9 @@ template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 // GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
 
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSERKS0_
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
 template struct __declspec(dllexport) C<int>;
 
@@ -50,7 +60,7 @@ void use() {
   // MSC: call void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
   // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
   c.not_to_be_exported(); // implicitly instantiated here
-};
+}
 
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE25to_be_exported_explicitlyEv
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 b070259c2f048..fa44f3aaa6e8a 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
@@ -1,10 +1,18 @@
-// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
-// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
-// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | \
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport
 
 // Test that __declspec(dllimport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllimport explicitly.
 
+// MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllimport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllimport.cpp
+
 #define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
@@ -46,7 +54,7 @@ void use() {
   // MSC: call void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
   // GNU: call void @_ZN1CIiE18not_to_be_importedEv
   c.not_to_be_imported(); // implicitly instantiated here
-};
+}
 
 // MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
 // GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv

>From bdbeeac2ccefd653641ab115edf58408d8c12d91 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Mon, 1 Dec 2025 21:15:38 +0900
Subject: [PATCH 05/20] add tests for the class-level attributes

---
 ...t_instantiation.exclude_from_dllexport.cpp | 32 +++++++++++++++++
 ...t_instantiation.exclude_from_dllimport.cpp | 34 +++++++++++++++++++
 2 files changed, 66 insertions(+)

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 a2d8e37acb626..eba5f24f2d5ae 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
@@ -37,12 +37,29 @@ template <class T> void C<T>::to_be_exported_explicitly() noexcept {}
 template <class T> void C<T>::not_to_be_exported() noexcept {}
 template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 
+// Attach the attribute to class template declaration instead of instantiation declaration.
+template <class T>
+struct __declspec(dllexport) D {
+  // This should be exported by the class-level attribute.
+  void to_be_exported() noexcept;
+
+  // This also should be exported by the class-level attribute but currently not.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_exported() noexcept;
+};
+
+template <class T> void D<T>::to_be_exported() noexcept {}
+template <class T> void D<T>::also_to_be_exported() noexcept {}
+
 // MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$D at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?also_to_be_exported@?$D at H@@QEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE14to_be_exportedEv = comdat any
 // GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE19also_to_be_exportedEv = comdat any
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
@@ -50,6 +67,12 @@ template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
 template struct __declspec(dllexport) C<int>;
 
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$D at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1DIiE14to_be_exportedEv
+template struct D<int>;
+
 void use() {
   C<int> c;
 
@@ -60,6 +83,12 @@ void use() {
   // MSC: call void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
   // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
   c.not_to_be_exported(); // implicitly instantiated here
+
+  D<int> d;
+
+  // MSC: call void @"?also_to_be_exported@?$D at H@@QEAAXXZ"
+  // GNU: call void @_ZN1DIiE19also_to_be_exportedEv
+  d.also_to_be_exported(); // implicitly instantiated here
 }
 
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
@@ -67,3 +96,6 @@ void use() {
 
 // MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define linkonce_odr dso_local void @"?also_to_be_exported@?$D at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_exportedEv
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 fa44f3aaa6e8a..f263ff070d852 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
@@ -36,10 +36,28 @@ template <class T> void C<T>::to_be_imported() noexcept {}
 template <class T> void C<T>::not_to_be_imported() noexcept {}
 template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 
+// Attach the attribute to class template declaration instead of instantiation declaration.
+template <class T>
+struct __declspec(dllimport) D {
+  // This will be imported by the class-level attribute.
+  void to_be_imported() noexcept;
+
+  // This also should be imported by the class-level attribute but currently not.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_imported() noexcept;
+};
+
+template <class T> void D<T>::to_be_imported() noexcept {}
+template <class T> void D<T>::also_to_be_imported() noexcept {}
+
 // MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
+// MSC: $"?also_to_be_imported@?$D at H@@QEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
+// GNU: $_ZN1DIiE19also_to_be_importedEv = comdat any
+
 extern template struct __declspec(dllimport) C<int>;
 
+extern template struct D<int>;
+
 void use() {
   C<int> c;
 
@@ -54,6 +72,16 @@ void use() {
   // MSC: call void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
   // GNU: call void @_ZN1CIiE18not_to_be_importedEv
   c.not_to_be_imported(); // implicitly instantiated here
+
+  D<int> d;
+
+  // MSC: call void @"?to_be_imported@?$D at H@@QEAAXXZ"
+  // GNU: call void @_ZN1DIiE14to_be_importedEv
+  d.to_be_imported(); // implicitly instantiated here
+
+  // MSC: call void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
+  // GNU: call void @_ZN1DIiE19also_to_be_importedEv
+  d.also_to_be_imported(); // implicitly instantiated here
 }
 
 // MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
@@ -64,3 +92,9 @@ void use() {
 
 // MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv
+
+// MSC: declare dllimport void @"?to_be_imported@?$D at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1DIiE14to_be_importedEv
+
+// MSC: define linkonce_odr dso_local void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_importedEv

>From bf8df954888217b07b5c5f99f0b98cb5d58e0e6d Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sun, 30 Nov 2025 07:37:12 +0900
Subject: [PATCH 06/20] add tests for virtual member functions

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++++++++++++++++
 ...t_instantiation.exclude_from_dllimport.cpp | 69 +++++++++++++++++++
 2 files changed, 133 insertions(+)

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 eba5f24f2d5ae..4bff5a828f34c 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
@@ -50,16 +50,54 @@ struct __declspec(dllexport) D {
 template <class T> void D<T>::to_be_exported() noexcept {}
 template <class T> void D<T>::also_to_be_exported() noexcept {}
 
+// Interaction with VTables.
+template <class T>
+struct E {
+  // This will be instanciated by the explicit template instantiation definition.
+  virtual void to_be_exported() noexcept;
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() noexcept;
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void to_be_exported_explicitly() noexcept;
+};
+
+template <class T> void E<T>::to_be_exported() noexcept {}
+template <class T> void E<T>::to_be_instantiated() noexcept {}
+template <class T> void E<T>::to_be_exported_explicitly() noexcept {}
+
 // MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E at I@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?also_to_be_exported@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E at I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E at I@@UEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
 // GNU: $_ZN1DIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
 // GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
 // GNU: $_ZN1DIiE19also_to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at I@@6B@")
+// MSC: @"??_7?$E at H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$E at I@@6B@" = unnamed_addr
+// GNU:@_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
+// GNU:@_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
@@ -73,6 +111,22 @@ template struct __declspec(dllexport) C<int>;
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1DIiE14to_be_exportedEv
 template struct D<int>;
 
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at XZ"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$E at H@@UEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2ERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1ERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiE14to_be_exportedEv
+template struct __declspec(dllexport) E<int>;
+
+// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$E at I@@UEAAXXZ"
+// GNU: define weak_odr dso_local{{.*}} void @_ZN1EIjE14to_be_exportedEv
+template struct E<unsigned int>;
+
 void use() {
   C<int> c;
 
@@ -99,3 +153,13 @@ void use() {
 
 // MSC: define linkonce_odr dso_local void @"?also_to_be_exported@?$D at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_exportedEv
+
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E at H@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1EIiE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN1EIiE25to_be_exported_explicitlyEv
+
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E at I@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1EIjE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN1EIjE25to_be_exported_explicitlyEv
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 f263ff070d852..6cb169bb5a4d8 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
@@ -49,15 +49,59 @@ struct __declspec(dllimport) D {
 template <class T> void D<T>::to_be_imported() noexcept {}
 template <class T> void D<T>::also_to_be_imported() noexcept {}
 
+// Interaction with VTables.
+template <class T>
+struct E {
+  // For the MSVC ABI: this constructor causes implicit instantiation of
+  // the VTable, which should trigger instantiating all virtual member
+  // functions regardless `exclude_from_explicit_instantiation` but currently not.
+  // For the Itanium ABI: Emitting the VTable is suppressed by implicit
+  // instantiation declaration so virtual member functions won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int);
+
+  // This constructor doesn't trigger the instantiation of the VTable.
+  // In this case, declaration of virtual member functions are absent too.
+  explicit E(long);
+
+  // The body of this shouldn't be emitted since instantiation is suppressed
+  // by the explicit instantiation declaration.
+  virtual void to_be_imported() noexcept;
+
+  // The body of this should be emitted if the VTable is instantiated, even if
+  // the instantiation of this class template is declared with dllimport.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() noexcept;
+
+  // The body of this shouldn't be emitted since that comes from an external DLL.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void to_be_imported_explicitly() noexcept;
+
+};
+
+template <class T> E<T>::E(int) {}
+template <class T> E<T>::E(long) {}
+template <class T> void E<T>::to_be_imported() noexcept {}
+template <class T> void E<T>::to_be_instantiated() noexcept {}
+
 // MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?also_to_be_imported@?$D at H@@QEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
 // GNU: $_ZN1DIiE19also_to_be_importedEv = comdat any
+// GNU: @_ZTV1EIiE = external dllimport unnamed_addr
+// GNU: @_ZTV1EIjE = external unnamed_addr
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$E at H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at I@@6B@")
+// MSC: @"??_S?$E at H@@6B@" =
+// MSC: @"??_7?$E at I@@6B@" =
 
 extern template struct __declspec(dllimport) C<int>;
 
 extern template struct D<int>;
 
+extern template struct __declspec(dllimport) E<int>;      // $E at H, 1EIiE
+extern template struct E<unsigned>;                       // $E at I, 1EIjE
+extern template struct __declspec(dllimport) E<long int>; // $E at J, 1EIlE
+extern template struct E<unsigned long int>;              // $E at K, 1EImE
+
 void use() {
   C<int> c;
 
@@ -82,6 +126,14 @@ void use() {
   // MSC: call void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
   // GNU: call void @_ZN1DIiE19also_to_be_importedEv
   d.also_to_be_imported(); // implicitly instantiated here
+
+  E<int> ei{1};
+
+  E<unsigned> ej{1};
+
+  E<long int> el{1L};
+
+  E<unsigned long int> eu{1L};
 }
 
 // MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
@@ -98,3 +150,20 @@ void use() {
 
 // MSC: define linkonce_odr dso_local void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_importedEv
+
+// MSC: declare dllimport noundef ptr @"??0?$E at J@@QEAA at J@Z"
+// MSC: declare dso_local noundef ptr @"??0?$E at K@@QEAA at J@Z"
+// GNU: define linkonce_odr dso_local void @_ZN1EIiEC1Ei
+// GNU: define linkonce_odr dso_local void @_ZN1EIjEC1Ei
+// GNU: declare dllimport void @_ZN1EIlEC1El
+// GNU: declare dso_local void @_ZN1EImEC1El
+// GNU: define linkonce_odr dso_local void @_ZN1EIiEC2Ei
+// GNU: define linkonce_odr dso_local void @_ZN1EIjEC2Ei
+
+// MSC: declare dllimport void @"?to_be_imported@?$E at H@@UEAAXXZ"
+// MSC: declare dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at H@@UEAAXXZ"
+
+// MSC: declare dso_local void @"?to_be_imported@?$E at I@@UEAAXXZ"
+// MSC: declare dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at I@@UEAAXXZ"

>From 5a16b110f4efc41bb1c64d601061d9abff5a472c Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Dec 2025 21:49:19 +0900
Subject: [PATCH 07/20] fix tests

---
 ...t_instantiation.exclude_from_dllexport.cpp | 46 +++++++++++--------
 ...t_instantiation.exclude_from_dllimport.cpp | 44 +++++++++---------
 2 files changed, 47 insertions(+), 43 deletions(-)

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 4bff5a828f34c..2f6767bc96142 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
@@ -40,15 +40,11 @@ template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
 struct __declspec(dllexport) D {
-  // This should be exported by the class-level attribute.
-  void to_be_exported() noexcept;
-
-  // This also should be exported by the class-level attribute but currently not.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_exported() noexcept;
+  // This will be exported if and only if no explicit instantiations are provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_exported_iff_no_explicit_instantiation() noexcept;
 };
 
-template <class T> void D<T>::to_be_exported() noexcept {}
-template <class T> void D<T>::also_to_be_exported() noexcept {}
+template <class T> void D<T>::to_be_exported_iff_no_explicit_instantiation() noexcept {}
 
 // Interaction with VTables.
 template <class T>
@@ -70,23 +66,23 @@ template <class T> void E<T>::to_be_instantiated() noexcept {}
 template <class T> void E<T>::to_be_exported_explicitly() noexcept {}
 
 // MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported@?$D at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$E at H@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$E at I@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?also_to_be_exported@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_instantiated@?$E at H@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$E at H@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_instantiated@?$E at I@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_explicitly@?$E at I@@UEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
-// GNU: $_ZN1DIiE14to_be_exportedEv = comdat any
 // GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
 // GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
 // GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
-// GNU: $_ZN1DIiE19also_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
 // GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
 // GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
 // GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
@@ -106,10 +102,10 @@ template <class T> void E<T>::to_be_exported_explicitly() noexcept {}
 template struct __declspec(dllexport) C<int>;
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$D at H@@QEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1DIiE14to_be_exportedEv
-template struct D<int>;
+template struct D<int>; // No dllexport here.
+// Don't provide explicit instantiation for D<unsigned>.
+
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0 at AEBU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at XZ"
@@ -127,6 +123,8 @@ template struct __declspec(dllexport) E<int>;
 // GNU: define weak_odr dso_local{{.*}} void @_ZN1EIjE14to_be_exportedEv
 template struct E<unsigned int>;
 
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at I@@QEAAAEAU0 at AEBU0@@Z"
+
 void use() {
   C<int> c;
 
@@ -138,11 +136,17 @@ void use() {
   // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
   c.not_to_be_exported(); // implicitly instantiated here
 
-  D<int> d;
+  D<int> di;
+
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
+  // GNU: call void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv
+  di.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
+
+  D<unsigned> dj;
 
-  // MSC: call void @"?also_to_be_exported@?$D at H@@QEAAXXZ"
-  // GNU: call void @_ZN1DIiE19also_to_be_exportedEv
-  d.also_to_be_exported(); // implicitly instantiated here
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
+  // GNU: call void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv
+  dj.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 }
 
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
@@ -151,8 +155,10 @@ void use() {
 // MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_exportedEv
 
-// MSC: define linkonce_odr dso_local void @"?also_to_be_exported@?$D at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_exportedEv
+// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv
+// GNU: define weak_odr dso_local dllexport void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv
 
 // MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
 // MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E at H@@UEAAXXZ"
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 6cb169bb5a4d8..ff5298ec56605 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
@@ -39,15 +39,11 @@ template <class T> void C<T>::not_to_be_instantiated() noexcept {}
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
 struct __declspec(dllimport) D {
-  // This will be imported by the class-level attribute.
-  void to_be_imported() noexcept;
-
-  // This also should be imported by the class-level attribute but currently not.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_imported() noexcept;
+  // This will be imported if and only if no explicit instantiations are provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_imported_iff_no_explicit_instantiation() noexcept;
 };
 
-template <class T> void D<T>::to_be_imported() noexcept {}
-template <class T> void D<T>::also_to_be_imported() noexcept {}
+template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() noexcept {}
 
 // Interaction with VTables.
 template <class T>
@@ -82,9 +78,9 @@ template <class T> void E<T>::to_be_imported() noexcept {}
 template <class T> void E<T>::to_be_instantiated() noexcept {}
 
 // MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?also_to_be_imported@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
-// GNU: $_ZN1DIiE19also_to_be_importedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
 // GNU: @_ZTV1EIiE = external dllimport unnamed_addr
 // GNU: @_ZTV1EIjE = external unnamed_addr
 
@@ -95,7 +91,8 @@ template <class T> void E<T>::to_be_instantiated() noexcept {}
 
 extern template struct __declspec(dllimport) C<int>;
 
-extern template struct D<int>;
+extern template struct D<int>; // No dllimport here.
+// Don't provide explicit instantiation for D<unsigned>.
 
 extern template struct __declspec(dllimport) E<int>;      // $E at H, 1EIiE
 extern template struct E<unsigned>;                       // $E at I, 1EIjE
@@ -117,15 +114,17 @@ void use() {
   // GNU: call void @_ZN1CIiE18not_to_be_importedEv
   c.not_to_be_imported(); // implicitly instantiated here
 
-  D<int> d;
+  D<int> di;
 
-  // MSC: call void @"?to_be_imported@?$D at H@@QEAAXXZ"
-  // GNU: call void @_ZN1DIiE14to_be_importedEv
-  d.to_be_imported(); // implicitly instantiated here
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
+  // GNU: call void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv
+  di.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  // MSC: call void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
-  // GNU: call void @_ZN1DIiE19also_to_be_importedEv
-  d.also_to_be_imported(); // implicitly instantiated here
+  D<unsigned> dj;
+
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
+  // GNU: call void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv
+  dj.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
   E<int> ei{1};
 
@@ -133,7 +132,7 @@ void use() {
 
   E<long int> el{1L};
 
-  E<unsigned long int> eu{1L};
+  E<unsigned long int> em{1L};
 }
 
 // MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
@@ -145,11 +144,10 @@ void use() {
 // MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv
 
-// MSC: declare dllimport void @"?to_be_imported@?$D at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN1DIiE14to_be_importedEv
-
-// MSC: define linkonce_odr dso_local void @"?also_to_be_imported@?$D at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_importedEv
+// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv
+// GNU: declare dllimport void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv
 
 // MSC: declare dllimport noundef ptr @"??0?$E at J@@QEAA at J@Z"
 // MSC: declare dso_local noundef ptr @"??0?$E at K@@QEAA at J@Z"

>From d40c7412e780977bd7830704a17a9e32f1b075d9 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Dec 2025 21:49:45 +0900
Subject: [PATCH 08/20] instantiate excluded virtual member functions

---
 clang/lib/Sema/SemaDeclCXX.cpp | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 27dd89fe15ec1..77bd30599e1bf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -19118,8 +19118,23 @@ bool Sema::DefineUsedVTables() {
         }
       }
 
-      if (IsExplicitInstantiationDeclaration)
+      if (IsExplicitInstantiationDeclaration) {
         DefineVTable = false;
+
+        // Ensure the instance of a virtual member function which is declared
+        // with `__attribute__((exclude_from_explicit_instantiation))` is
+        // accessible from the VTable.
+        for (Decl *decl : Class->decls()) {
+          auto *Method = dyn_cast<CXXMethodDecl>(decl);
+          if (!Method || !Method->isVirtual())
+            continue;
+
+          if (Method->hasAttr<ExcludeFromExplicitInstantiationAttr>()) {
+            MarkFunctionReferenced(Loc, Method);
+            DefinedAnything = true;
+          }
+        }
+      }
     }
 
     // The exception specifications for all virtual members may be needed even

>From 73b9cf48eec841a6a13b89141cd606a92ab1a0c7 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Dec 2025 21:49:56 +0900
Subject: [PATCH 09/20] update test

---
 ...m_explicit_instantiation.exclude_from_dllimport.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

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 ff5298ec56605..5106dd72aa7aa 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
@@ -49,8 +49,8 @@ template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() noe
 template <class T>
 struct E {
   // For the MSVC ABI: this constructor causes implicit instantiation of
-  // the VTable, which should trigger instantiating all virtual member
-  // functions regardless `exclude_from_explicit_instantiation` but currently not.
+  // the VTable, which triggers instantiating all virtual member
+  // functions regardless `exclude_from_explicit_instantiation`.
   // For the Itanium ABI: Emitting the VTable is suppressed by implicit
   // instantiation declaration so virtual member functions won't be instantiated.
   EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int);
@@ -79,6 +79,8 @@ template <class T> void E<T>::to_be_instantiated() noexcept {}
 
 // MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E at I@@UEAAXXZ" = comdat any
 // GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
 // GNU: $_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
 // GNU: @_ZTV1EIiE = external dllimport unnamed_addr
@@ -159,9 +161,9 @@ void use() {
 // GNU: define linkonce_odr dso_local void @_ZN1EIjEC2Ei
 
 // MSC: declare dllimport void @"?to_be_imported@?$E at H@@UEAAXXZ"
-// MSC: declare dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
 // MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at H@@UEAAXXZ"
 
 // MSC: declare dso_local void @"?to_be_imported@?$E at I@@UEAAXXZ"
-// MSC: declare dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
 // MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at I@@UEAAXXZ"

>From f2f249690fec9b8245dc17cdcfc605fd632a2fff Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 10 Dec 2025 20:58:20 +0900
Subject: [PATCH 10/20] post-merge fix

---
 ..._explicit_instantiation.exclude_from_dllexport.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

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 2f6767bc96142..369d505a2f6b4 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
@@ -96,26 +96,34 @@ template <class T> void E<T>::to_be_exported_explicitly() noexcept {}
 // GNU:@_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0@$$QEAU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSEOS0_
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
 template struct __declspec(dllexport) C<int>;
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0@$$QEAU0@@Z"
 // GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSEOS0_
 template struct D<int>; // No dllexport here.
 // Don't provide explicit instantiation for D<unsigned>.
 
-
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0@$$QEAU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at XZ"
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA@$$QEAU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$E at H@@UEAAXXZ"
 // GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSEOS0_
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2Ev
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1Ev
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2ERKS0_
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1ERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2EOS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1EOS0_
 // GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiE14to_be_exportedEv
 template struct __declspec(dllexport) E<int>;
 
@@ -124,6 +132,7 @@ template struct __declspec(dllexport) E<int>;
 template struct E<unsigned int>;
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at I@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at I@@QEAAAEAU0@$$QEAU0@@Z"
 
 void use() {
   C<int> c;

>From 69378a59b88f3324c137732632ae4a1c7e8d4e7a Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 10 Dec 2025 20:58:36 +0900
Subject: [PATCH 11/20] drop noexcept from tests

---
 ...t_instantiation.exclude_from_dllexport.cpp | 32 +++++++++----------
 ...t_instantiation.exclude_from_dllimport.cpp | 28 ++++++++--------
 2 files changed, 30 insertions(+), 30 deletions(-)

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 369d505a2f6b4..c955c932a3619 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
@@ -19,51 +19,51 @@ template <class T>
 struct C {
   // This will be instantiated explicitly as an exported function because it
   // inherits dllexport from the class instantiation.
-  void to_be_exported() noexcept;
+  void to_be_exported();
 
   // This will be instantiated implicitly as an exported function because it is
   // marked as dllexport explicitly.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly();
 
   // This will be instantiated implicitly but won't be exported.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
 
   // This won't be instantiated.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
 };
 
-template <class T> void C<T>::to_be_exported() noexcept {}
-template <class T> void C<T>::to_be_exported_explicitly() noexcept {}
-template <class T> void C<T>::not_to_be_exported() noexcept {}
-template <class T> void C<T>::not_to_be_instantiated() noexcept {}
+template <class T> void C<T>::to_be_exported() {}
+template <class T> void C<T>::to_be_exported_explicitly() {}
+template <class T> void C<T>::not_to_be_exported() {}
+template <class T> void C<T>::not_to_be_instantiated() {}
 
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
 struct __declspec(dllexport) D {
   // This will be exported if and only if no explicit instantiations are provided.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_exported_iff_no_explicit_instantiation() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_exported_iff_no_explicit_instantiation();
 };
 
-template <class T> void D<T>::to_be_exported_iff_no_explicit_instantiation() noexcept {}
+template <class T> void D<T>::to_be_exported_iff_no_explicit_instantiation() {}
 
 // Interaction with VTables.
 template <class T>
 struct E {
   // This will be instanciated by the explicit template instantiation definition.
-  virtual void to_be_exported() noexcept;
+  virtual void to_be_exported();
 
   // This will be instantiated by the VTable definition, regardless of
   // `exclude_from_explicit_instantiation`.
   // The dllexport attribute won't be inherited.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
 
   // This too, but will be exported by the member attribute.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void to_be_exported_explicitly() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void to_be_exported_explicitly();
 };
 
-template <class T> void E<T>::to_be_exported() noexcept {}
-template <class T> void E<T>::to_be_instantiated() noexcept {}
-template <class T> void E<T>::to_be_exported_explicitly() noexcept {}
+template <class T> void E<T>::to_be_exported() {}
+template <class T> void E<T>::to_be_instantiated() {}
+template <class T> void E<T>::to_be_exported_explicitly() {}
 
 // MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$E at H@@UEAAXXZ" = comdat any
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 5106dd72aa7aa..492a83767c7e5 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
@@ -19,31 +19,31 @@ template <class T>
 struct C {
   // This will be instantiated explicitly as an imported function because it
   // inherits dllimport from the class instantiation.
-  void to_be_imported() noexcept;
+  void to_be_imported();
 
   // This will be instantiated implicitly as an imported function because it is
   // marked as dllimport explicitly.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly();
 
   // This will be instantiated implicitly but won't be imported.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported();
 
   // This won't be instantiated.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
 };
 
-template <class T> void C<T>::to_be_imported() noexcept {}
-template <class T> void C<T>::not_to_be_imported() noexcept {}
-template <class T> void C<T>::not_to_be_instantiated() noexcept {}
+template <class T> void C<T>::to_be_imported() {}
+template <class T> void C<T>::not_to_be_imported() {}
+template <class T> void C<T>::not_to_be_instantiated() {}
 
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
 struct __declspec(dllimport) D {
   // This will be imported if and only if no explicit instantiations are provided.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_imported_iff_no_explicit_instantiation() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_imported_iff_no_explicit_instantiation();
 };
 
-template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() noexcept {}
+template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() {}
 
 // Interaction with VTables.
 template <class T>
@@ -61,21 +61,21 @@ struct E {
 
   // The body of this shouldn't be emitted since instantiation is suppressed
   // by the explicit instantiation declaration.
-  virtual void to_be_imported() noexcept;
+  virtual void to_be_imported();
 
   // The body of this should be emitted if the VTable is instantiated, even if
   // the instantiation of this class template is declared with dllimport.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
 
   // The body of this shouldn't be emitted since that comes from an external DLL.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void to_be_imported_explicitly() noexcept;
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void to_be_imported_explicitly();
 
 };
 
 template <class T> E<T>::E(int) {}
 template <class T> E<T>::E(long) {}
-template <class T> void E<T>::to_be_imported() noexcept {}
-template <class T> void E<T>::to_be_instantiated() noexcept {}
+template <class T> void E<T>::to_be_imported() {}
+template <class T> void E<T>::to_be_instantiated() {}
 
 // MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any

>From 7d9eb14e8e255fe3942b8b598bc52cabab6cea1e Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 10 Dec 2025 20:58:40 +0900
Subject: [PATCH 12/20] revise logic

---
 clang/lib/Sema/SemaDeclCXX.cpp | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3ac8011c030bc..1a470c7dd3b0e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -19119,23 +19119,18 @@ bool Sema::DefineUsedVTables() {
         }
       }
 
-      if (IsExplicitInstantiationDeclaration) {
+      if (IsExplicitInstantiationDeclaration &&
+          llvm::none_of(Class->decls(), [](Decl *decl) {
+            // If the class has a virtual member function declared with
+            // `__attribute__((exclude_from_explicit_instantiation))`, the
+            // explicit instantiation declaration shouldn't suppress emitting
+            // the vtable to ensure that the excluded member function is
+            // accessible through the vtable.
+            auto *Method = dyn_cast<CXXMethodDecl>(decl);
+            return Method && Method->isVirtual() &&
+                   Method->hasAttr<ExcludeFromExplicitInstantiationAttr>();
+          }))
         DefineVTable = false;
-
-        // Ensure the instance of a virtual member function which is declared
-        // with `__attribute__((exclude_from_explicit_instantiation))` is
-        // accessible from the VTable.
-        for (Decl *decl : Class->decls()) {
-          auto *Method = dyn_cast<CXXMethodDecl>(decl);
-          if (!Method || !Method->isVirtual())
-            continue;
-
-          if (Method->hasAttr<ExcludeFromExplicitInstantiationAttr>()) {
-            MarkFunctionReferenced(Loc, Method);
-            DefinedAnything = true;
-          }
-        }
-      }
     }
 
     // The exception specifications for all virtual members may be needed even

>From 6e487588dfca444d0f3ee2315bc5fc49cad1534d Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 25 Dec 2025 21:19:37 +0900
Subject: [PATCH 13/20] store to a named variable

---
 clang/lib/Sema/SemaDeclCXX.cpp | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 1a470c7dd3b0e..dc46e50171c93 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -19119,18 +19119,21 @@ bool Sema::DefineUsedVTables() {
         }
       }
 
-      if (IsExplicitInstantiationDeclaration &&
-          llvm::none_of(Class->decls(), [](Decl *decl) {
-            // If the class has a virtual member function declared with
-            // `__attribute__((exclude_from_explicit_instantiation))`, the
-            // explicit instantiation declaration shouldn't suppress emitting
-            // the vtable to ensure that the excluded member function is
-            // accessible through the vtable.
-            auto *Method = dyn_cast<CXXMethodDecl>(decl);
-            return Method && Method->isVirtual() &&
-                   Method->hasAttr<ExcludeFromExplicitInstantiationAttr>();
-          }))
-        DefineVTable = false;
+      if (IsExplicitInstantiationDeclaration) {
+        const bool HasExcludeFromExplicitInstantiation =
+            llvm::any_of(Class->decls(), [](Decl *decl) {
+              // If the class has a virtual member function declared with
+              // `__attribute__((exclude_from_explicit_instantiation))`, the
+              // explicit instantiation declaration shouldn't suppress emitting
+              // the vtable to ensure that the excluded member function is
+              // accessible through the vtable.
+              auto *Method = dyn_cast<CXXMethodDecl>(decl);
+              return Method && Method->isVirtual() &&
+                     Method->hasAttr<ExcludeFromExplicitInstantiationAttr>();
+            });
+        if (!HasExcludeFromExplicitInstantiation)
+          DefineVTable = false;
+      }
     }
 
     // The exception specifications for all virtual members may be needed even

>From d9c78ee6f3d1149484e95b0111e6847dae3a06c0 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 25 Dec 2025 21:16:19 +0900
Subject: [PATCH 14/20] add a comment to explain silencing implicit checks

---
 ...xclude_from_explicit_instantiation.exclude_from_dllexport.cpp | 1 +
 ...xclude_from_explicit_instantiation.exclude_from_dllimport.cpp | 1 +
 2 files changed, 2 insertions(+)

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 c955c932a3619..7a9d1343f451e 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
@@ -8,6 +8,7 @@
 // Test that __declspec(dllexport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllexport explicitly.
 
+// Silence --implicit-check-not=dllexport.
 // MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
 // MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
 // GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
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 492a83767c7e5..353e7f8facc3b 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
@@ -8,6 +8,7 @@
 // Test that __declspec(dllimport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllimport explicitly.
 
+// Silence --implicit-check-not=dllimport.
 // MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp
 // MSC: source_filename = {{.*}}exclude_from_dllimport.cpp
 // GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp

>From a8a745952993fcb4fd7495fb263ea2d073947b45 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 21 Jan 2026 21:03:54 +0900
Subject: [PATCH 15/20] nit

---
 ...ude_from_explicit_instantiation.exclude_from_dllexport.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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 7a9d1343f451e..d5c942c2d82d6 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
@@ -93,8 +93,8 @@ template <class T> void E<T>::to_be_exported_explicitly() {}
 // MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at I@@6B@")
 // MSC: @"??_7?$E at H@@6B@" = dllexport unnamed_addr
 // MSC: @"??_7?$E at I@@6B@" = unnamed_addr
-// GNU:@_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
-// GNU:@_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
+// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
 
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
 // MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0@$$QEAU0@@Z"

>From 8f6b530c5b6d7e0d8a23ff27ab85faff38aecddf Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 21 Jan 2026 21:31:59 +0900
Subject: [PATCH 16/20] drop isVirtual

---
 clang/lib/Sema/SemaDeclCXX.cpp | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index dc46e50171c93..df381736f24ce 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -19121,15 +19121,14 @@ bool Sema::DefineUsedVTables() {
 
       if (IsExplicitInstantiationDeclaration) {
         const bool HasExcludeFromExplicitInstantiation =
-            llvm::any_of(Class->decls(), [](Decl *decl) {
-              // If the class has a virtual member function declared with
+            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 shouldn't suppress emitting
-              // the vtable to ensure that the excluded member function is
-              // accessible through the vtable.
-              auto *Method = dyn_cast<CXXMethodDecl>(decl);
-              return Method && Method->isVirtual() &&
-                     Method->hasAttr<ExcludeFromExplicitInstantiationAttr>();
+              // 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;

>From d87b50895e8392c59ce25f270a3880222de99314 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 21 Feb 2026 15:38:30 +0900
Subject: [PATCH 17/20] s/EXCLUDE_FROM_EXPLICIT_INSTANTIATION/EXCLUDE_ATTR/

---
 ...icit_instantiation.exclude_from_dllexport.cpp | 14 +++++++-------
 ...icit_instantiation.exclude_from_dllimport.cpp | 16 ++++++++--------
 2 files changed, 15 insertions(+), 15 deletions(-)

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 d5c942c2d82d6..76b3a5c3d94ae 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
@@ -14,7 +14,7 @@
 // GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
 // GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
 
-#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
+#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
 struct C {
@@ -24,13 +24,13 @@ struct C {
 
   // This will be instantiated implicitly as an exported function because it is
   // marked as dllexport explicitly.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly();
+  EXCLUDE_ATTR __declspec(dllexport) void to_be_exported_explicitly();
 
   // This will be instantiated implicitly but won't be exported.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+  EXCLUDE_ATTR void not_to_be_exported();
 
   // This won't be instantiated.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+  EXCLUDE_ATTR void not_to_be_instantiated();
 };
 
 template <class T> void C<T>::to_be_exported() {}
@@ -42,7 +42,7 @@ template <class T> void C<T>::not_to_be_instantiated() {}
 template <class T>
 struct __declspec(dllexport) D {
   // This will be exported if and only if no explicit instantiations are provided.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_exported_iff_no_explicit_instantiation();
+  EXCLUDE_ATTR void to_be_exported_iff_no_explicit_instantiation();
 };
 
 template <class T> void D<T>::to_be_exported_iff_no_explicit_instantiation() {}
@@ -56,10 +56,10 @@ struct E {
   // This will be instantiated by the VTable definition, regardless of
   // `exclude_from_explicit_instantiation`.
   // The dllexport attribute won't be inherited.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+  EXCLUDE_ATTR virtual void to_be_instantiated();
 
   // This too, but will be exported by the member attribute.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void to_be_exported_explicitly();
+  EXCLUDE_ATTR __declspec(dllexport) virtual void to_be_exported_explicitly();
 };
 
 template <class T> void E<T>::to_be_exported() {}
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 353e7f8facc3b..b89d5deacb3dd 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
@@ -14,7 +14,7 @@
 // GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp
 // GNU: source_filename = {{.*}}exclude_from_dllimport.cpp
 
-#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
+#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
 struct C {
@@ -24,13 +24,13 @@ struct C {
 
   // This will be instantiated implicitly as an imported function because it is
   // marked as dllimport explicitly.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly();
+  EXCLUDE_ATTR __declspec(dllimport) void to_be_imported_explicitly();
 
   // This will be instantiated implicitly but won't be imported.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported();
+  EXCLUDE_ATTR void not_to_be_imported();
 
   // This won't be instantiated.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+  EXCLUDE_ATTR void not_to_be_instantiated();
 };
 
 template <class T> void C<T>::to_be_imported() {}
@@ -41,7 +41,7 @@ template <class T> void C<T>::not_to_be_instantiated() {}
 template <class T>
 struct __declspec(dllimport) D {
   // This will be imported if and only if no explicit instantiations are provided.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_imported_iff_no_explicit_instantiation();
+  EXCLUDE_ATTR void to_be_imported_iff_no_explicit_instantiation();
 };
 
 template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() {}
@@ -54,7 +54,7 @@ struct E {
   // functions regardless `exclude_from_explicit_instantiation`.
   // For the Itanium ABI: Emitting the VTable is suppressed by implicit
   // instantiation declaration so virtual member functions won't be instantiated.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int);
+  EXCLUDE_ATTR explicit E(int);
 
   // This constructor doesn't trigger the instantiation of the VTable.
   // In this case, declaration of virtual member functions are absent too.
@@ -66,10 +66,10 @@ struct E {
 
   // The body of this should be emitted if the VTable is instantiated, even if
   // the instantiation of this class template is declared with dllimport.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+  EXCLUDE_ATTR virtual void to_be_instantiated();
 
   // The body of this shouldn't be emitted since that comes from an external DLL.
-  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void to_be_imported_explicitly();
+  EXCLUDE_ATTR __declspec(dllimport) virtual void to_be_imported_explicitly();
 
 };
 

>From a37e67c56d06253fc2d6bbe2b76c35bc1037f096 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 21 Feb 2026 18:13:32 +0900
Subject: [PATCH 18/20] make class names symbolic

---
 ...t_instantiation.exclude_from_dllexport.cpp | 215 +++++++++---------
 ...t_instantiation.exclude_from_dllimport.cpp | 147 ++++++------
 2 files changed, 182 insertions(+), 180 deletions(-)

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 76b3a5c3d94ae..f226b636062e1 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
@@ -17,7 +17,7 @@
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
-struct C {
+struct BasicCase {
   // This will be instantiated explicitly as an exported function because it
   // inherits dllexport from the class instantiation.
   void to_be_exported();
@@ -33,23 +33,24 @@ struct C {
   EXCLUDE_ATTR void not_to_be_instantiated();
 };
 
-template <class T> void C<T>::to_be_exported() {}
-template <class T> void C<T>::to_be_exported_explicitly() {}
-template <class T> void C<T>::not_to_be_exported() {}
-template <class T> void C<T>::not_to_be_instantiated() {}
+// Member functions can't be inlined since clang in MinGW mode doesn't export/import them that are inlined.
+template <class T> void BasicCase<T>::to_be_exported() {}
+template <class T> void BasicCase<T>::to_be_exported_explicitly() {}
+template <class T> void BasicCase<T>::not_to_be_exported() {}
+template <class T> void BasicCase<T>::not_to_be_instantiated() {}
 
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
-struct __declspec(dllexport) D {
+struct __declspec(dllexport) ExportWholeTemplate {
   // This will be exported if and only if no explicit instantiations are provided.
   EXCLUDE_ATTR void to_be_exported_iff_no_explicit_instantiation();
 };
 
-template <class T> void D<T>::to_be_exported_iff_no_explicit_instantiation() {}
+template <class T> void ExportWholeTemplate<T>::to_be_exported_iff_no_explicit_instantiation() {}
 
 // Interaction with VTables.
 template <class T>
-struct E {
+struct Polymorphic {
   // This will be instanciated by the explicit template instantiation definition.
   virtual void to_be_exported();
 
@@ -62,120 +63,120 @@ struct E {
   EXCLUDE_ATTR __declspec(dllexport) virtual void to_be_exported_explicitly();
 };
 
-template <class T> void E<T>::to_be_exported() {}
-template <class T> void E<T>::to_be_instantiated() {}
-template <class T> void E<T>::to_be_exported_explicitly() {}
-
-// MSC: $"?to_be_exported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported@?$E at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported@?$E at I@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?not_to_be_exported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$E at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$E at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$E at I@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$E at I@@UEAAXXZ" = comdat any
-// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
-// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
-// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
-// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
-// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
-// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
-// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
-// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
-// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
-
-// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at H@@6B@")
-// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at I@@6B@")
-// MSC: @"??_7?$E at H@@6B@" = dllexport unnamed_addr
-// MSC: @"??_7?$E at I@@6B@" = unnamed_addr
-// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
-// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C at H@@QEAAAEAU0@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSEOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv
-template struct __declspec(dllexport) C<int>;
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at H@@QEAAAEAU0@$$QEAU0@@Z"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSEOS0_
-template struct D<int>; // No dllexport here.
-// Don't provide explicit instantiation for D<unsigned>.
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E at H@@QEAAAEAU0@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at XZ"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E at H@@QEAA@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$E at H@@UEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSEOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2Ev
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1Ev
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2ERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1ERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2EOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1EOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiE14to_be_exportedEv
-template struct __declspec(dllexport) E<int>;
-
-// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$E at I@@UEAAXXZ"
-// GNU: define weak_odr dso_local{{.*}} void @_ZN1EIjE14to_be_exportedEv
-template struct E<unsigned int>;
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at I@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D at I@@QEAAAEAU0@$$QEAU0@@Z"
+template <class T> void Polymorphic<T>::to_be_exported() {}
+template <class T> void Polymorphic<T>::to_be_instantiated() {}
+template <class T> void Polymorphic<T>::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$BasicCase at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$Polymorphic at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$Polymorphic at I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$Polymorphic at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$Polymorphic at I@@UEAAXXZ" = comdat any
+// GNU: $_ZN9BasicCaseIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN11PolymorphicIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN11PolymorphicIjE14to_be_exportedEv = comdat any
+// GNU: $_ZN9BasicCaseIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN9BasicCaseIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN11PolymorphicIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN11PolymorphicIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN11PolymorphicIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN11PolymorphicIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at I@@6B@")
+// MSC: @"??_7?$Polymorphic at H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$Polymorphic at I@@6B@" = unnamed_addr
+// GNU: @_ZTV11PolymorphicIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
+// GNU: @_ZTV11PolymorphicIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at H@@QEAAAEAU0@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$BasicCase at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseIiEaSEOS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseIiE14to_be_exportedEv
+template struct __declspec(dllexport) BasicCase<int>;
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at H@@QEAAAEAU0@$$QEAU0@@Z"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateIiEaSEOS0_
+template struct ExportWholeTemplate<int>; // No dllexport here.
+// Don't provide explicit instantiation for ExportWholeTemplate<unsigned>.
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at H@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at H@@QEAAAEAU0@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA at XZ"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$Polymorphic at H@@UEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicIiEaSERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicIiEaSEOS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2ERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1ERKS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2EOS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1EOS0_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiE14to_be_exportedEv
+template struct __declspec(dllexport) Polymorphic<int>;
+
+// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$Polymorphic at I@@UEAAXXZ"
+// GNU: define weak_odr dso_local{{.*}} void @_ZN11PolymorphicIjE14to_be_exportedEv
+template struct Polymorphic<unsigned int>;
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at I@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at I@@QEAAAEAU0@$$QEAU0@@Z"
 
 void use() {
-  C<int> c;
+  BasicCase<int> c;
 
-  // MSC: call void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
-  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  // MSC: call void @"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseIiE25to_be_exported_explicitlyEv
   c.to_be_exported_explicitly(); // implicitly instantiated here
 
-  // MSC: call void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
-  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  // MSC: call void @"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseIiE18not_to_be_exportedEv
   c.not_to_be_exported(); // implicitly instantiated here
 
-  D<int> di;
+  ExportWholeTemplate<int> di;
 
-  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
-  // GNU: call void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ"
+  // GNU: call void @_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv
   di.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  D<unsigned> dj;
+  ExportWholeTemplate<unsigned> dj;
 
-  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
-  // GNU: call void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ"
+  // GNU: call void @_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv
   dj.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 }
 
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE25to_be_exported_explicitlyEv
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseIiE25to_be_exported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$C at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_exportedEv
+// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseIiE18not_to_be_exportedEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv
-// GNU: define weak_odr dso_local dllexport void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv
+// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv
+// GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E at H@@UEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1EIiE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN1EIiE25to_be_exported_explicitlyEv
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at H@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicIiE25to_be_exported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E at I@@UEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1EIjE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN1EIjE25to_be_exported_explicitlyEv
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at I@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicIjE25to_be_exported_explicitlyEv
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 b89d5deacb3dd..8a00f66269b0f 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
@@ -17,7 +17,7 @@
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 template <class T>
-struct C {
+struct BasicCase {
   // This will be instantiated explicitly as an imported function because it
   // inherits dllimport from the class instantiation.
   void to_be_imported();
@@ -33,32 +33,33 @@ struct C {
   EXCLUDE_ATTR void not_to_be_instantiated();
 };
 
-template <class T> void C<T>::to_be_imported() {}
-template <class T> void C<T>::not_to_be_imported() {}
-template <class T> void C<T>::not_to_be_instantiated() {}
+// Member functions can't be inlined since clang in MinGW mode doesn't export/import them that are inlined.
+template <class T> void BasicCase<T>::to_be_imported() {}
+template <class T> void BasicCase<T>::not_to_be_imported() {}
+template <class T> void BasicCase<T>::not_to_be_instantiated() {}
 
 // Attach the attribute to class template declaration instead of instantiation declaration.
 template <class T>
-struct __declspec(dllimport) D {
+struct __declspec(dllimport) ImportWholeTemplate {
   // This will be imported if and only if no explicit instantiations are provided.
   EXCLUDE_ATTR void to_be_imported_iff_no_explicit_instantiation();
 };
 
-template <class T> void D<T>::to_be_imported_iff_no_explicit_instantiation() {}
+template <class T> void ImportWholeTemplate<T>::to_be_imported_iff_no_explicit_instantiation() {}
 
 // Interaction with VTables.
 template <class T>
-struct E {
+struct Polymorphic {
   // For the MSVC ABI: this constructor causes implicit instantiation of
   // the VTable, which triggers instantiating all virtual member
   // functions regardless `exclude_from_explicit_instantiation`.
   // For the Itanium ABI: Emitting the VTable is suppressed by implicit
   // instantiation declaration so virtual member functions won't be instantiated.
-  EXCLUDE_ATTR explicit E(int);
+  EXCLUDE_ATTR explicit Polymorphic(int);
 
   // This constructor doesn't trigger the instantiation of the VTable.
   // In this case, declaration of virtual member functions are absent too.
-  explicit E(long);
+  explicit Polymorphic(long);
 
   // The body of this shouldn't be emitted since instantiation is suppressed
   // by the explicit instantiation declaration.
@@ -73,98 +74,98 @@ struct E {
 
 };
 
-template <class T> E<T>::E(int) {}
-template <class T> E<T>::E(long) {}
-template <class T> void E<T>::to_be_imported() {}
-template <class T> void E<T>::to_be_instantiated() {}
+template <class T> Polymorphic<T>::Polymorphic(int) {}
+template <class T> Polymorphic<T>::Polymorphic(long) {}
+template <class T> void Polymorphic<T>::to_be_imported() {}
+template <class T> void Polymorphic<T>::to_be_instantiated() {}
 
-// MSC: $"?not_to_be_imported@?$C at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$E at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$E at I@@UEAAXXZ" = comdat any
-// GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
-// GNU: $_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
-// GNU: @_ZTV1EIiE = external dllimport unnamed_addr
-// GNU: @_ZTV1EIjE = external unnamed_addr
+// MSC: $"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ" = comdat any
+// GNU: $_ZN9BasicCaseIiE18not_to_be_importedEv = comdat any
+// GNU: $_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
+// GNU: @_ZTV11PolymorphicIiE = external dllimport unnamed_addr
+// GNU: @_ZTV11PolymorphicIjE = external unnamed_addr
 
-// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$E at H@@6B@")
-// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E at I@@6B@")
-// MSC: @"??_S?$E at H@@6B@" =
-// MSC: @"??_7?$E at I@@6B@" =
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$Polymorphic at H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at I@@6B@")
+// MSC: @"??_S?$Polymorphic at H@@6B@" =
+// MSC: @"??_7?$Polymorphic at I@@6B@" =
 
-extern template struct __declspec(dllimport) C<int>;
+extern template struct __declspec(dllimport) BasicCase<int>;
 
-extern template struct D<int>; // No dllimport here.
-// Don't provide explicit instantiation for D<unsigned>.
+extern template struct ImportWholeTemplate<int>; // No dllimport here.
+// Don't provide explicit instantiation for ImportWholeTemplate<unsigned>.
 
-extern template struct __declspec(dllimport) E<int>;      // $E at H, 1EIiE
-extern template struct E<unsigned>;                       // $E at I, 1EIjE
-extern template struct __declspec(dllimport) E<long int>; // $E at J, 1EIlE
-extern template struct E<unsigned long int>;              // $E at K, 1EImE
+extern template struct __declspec(dllimport) Polymorphic<int>;
+extern template struct Polymorphic<unsigned>;
+extern template struct __declspec(dllimport) Polymorphic<long int>;
+extern template struct Polymorphic<unsigned long int>;
 
 void use() {
-  C<int> c;
+  BasicCase<int> c;
 
-  // MSC: call void @"?to_be_imported@?$C at H@@QEAAXXZ"
-  // GNU: call void @_ZN1CIiE14to_be_importedEv
+  // MSC: call void @"?to_be_imported@?$BasicCase at H@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseIiE14to_be_importedEv
   c.to_be_imported();
 
-  // MSC: call void @"?to_be_imported_explicitly@?$C at H@@QEAAXXZ"
-  // GNU: call void @_ZN1CIiE25to_be_imported_explicitlyEv
+  // MSC: call void @"?to_be_imported_explicitly@?$BasicCase at H@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseIiE25to_be_imported_explicitlyEv
   c.to_be_imported_explicitly(); // implicitly instantiated here
 
-  // MSC: call void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
-  // GNU: call void @_ZN1CIiE18not_to_be_importedEv
+  // MSC: call void @"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseIiE18not_to_be_importedEv
   c.not_to_be_imported(); // implicitly instantiated here
 
-  D<int> di;
+  ImportWholeTemplate<int> di;
 
-  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
-  // GNU: call void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ"
+  // GNU: call void @_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv
   di.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  D<unsigned> dj;
+  ImportWholeTemplate<unsigned> dj;
 
-  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
-  // GNU: call void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at I@@QEAAXXZ"
+  // GNU: call void @_ZN19ImportWholeTemplateIjE44to_be_imported_iff_no_explicit_instantiationEv
   dj.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  E<int> ei{1};
+  Polymorphic<int> ei{1};
 
-  E<unsigned> ej{1};
+  Polymorphic<unsigned> ej{1};
 
-  E<long int> el{1L};
+  Polymorphic<long int> el{1L};
 
-  E<unsigned long int> em{1L};
+  Polymorphic<unsigned long int> em{1L};
 }
 
-// MSC: declare dllimport void @"?to_be_imported@?$C at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv
+// MSC: declare dllimport void @"?to_be_imported@?$BasicCase at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN9BasicCaseIiE14to_be_importedEv
 
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$C at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN1CIiE25to_be_imported_explicitlyEv
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$BasicCase at H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN9BasicCaseIiE25to_be_imported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$C at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv
+// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseIiE18not_to_be_importedEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$D at H@@QEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$D at I@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv
-// GNU: declare dllimport void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv
+// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at I@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv
+// GNU: declare dllimport void @_ZN19ImportWholeTemplateIjE44to_be_imported_iff_no_explicit_instantiationEv
 
-// MSC: declare dllimport noundef ptr @"??0?$E at J@@QEAA at J@Z"
-// MSC: declare dso_local noundef ptr @"??0?$E at K@@QEAA at J@Z"
-// GNU: define linkonce_odr dso_local void @_ZN1EIiEC1Ei
-// GNU: define linkonce_odr dso_local void @_ZN1EIjEC1Ei
-// GNU: declare dllimport void @_ZN1EIlEC1El
-// GNU: declare dso_local void @_ZN1EImEC1El
-// GNU: define linkonce_odr dso_local void @_ZN1EIiEC2Ei
-// GNU: define linkonce_odr dso_local void @_ZN1EIjEC2Ei
+// MSC: declare dllimport noundef ptr @"??0?$Polymorphic at J@@QEAA at J@Z"
+// MSC: declare dso_local noundef ptr @"??0?$Polymorphic at K@@QEAA at J@Z"
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiEC1Ei
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjEC1Ei
+// GNU: declare dllimport void @_ZN11PolymorphicIlEC1El
+// GNU: declare dso_local void @_ZN11PolymorphicImEC1El
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiEC2Ei
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjEC2Ei
 
-// MSC: declare dllimport void @"?to_be_imported@?$E at H@@UEAAXXZ"
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at H@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at H@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported@?$Polymorphic at H@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at H@@UEAAXXZ"
 
-// MSC: declare dso_local void @"?to_be_imported@?$E at I@@UEAAXXZ"
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E at I@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E at I@@UEAAXXZ"
+// MSC: declare dso_local void @"?to_be_imported@?$Polymorphic at I@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at I@@UEAAXXZ"

>From 841d7803b8f718e062f31c5f861d8b8781a5fa70 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 21 Feb 2026 19:02:59 +0900
Subject: [PATCH 19/20] make template paramaters symbolic

---
 ...t_instantiation.exclude_from_dllexport.cpp | 193 +++++++++---------
 ...t_instantiation.exclude_from_dllimport.cpp | 123 +++++------
 2 files changed, 151 insertions(+), 165 deletions(-)

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 f226b636062e1..ed54167248ff9 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
@@ -16,6 +16,10 @@
 
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
+struct NoAttrTag {};
+struct WithExportTag {};
+struct ImplicitTag {};
+
 template <class T>
 struct BasicCase {
   // This will be instantiated explicitly as an exported function because it
@@ -67,116 +71,115 @@ template <class T> void Polymorphic<T>::to_be_exported() {}
 template <class T> void Polymorphic<T>::to_be_instantiated() {}
 template <class T> void Polymorphic<T>::to_be_exported_explicitly() {}
 
-// MSC: $"?to_be_exported@?$BasicCase at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported@?$Polymorphic at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported@?$Polymorphic at I@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ" = comdat any
-// MSC: $"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$Polymorphic at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$Polymorphic at I@@UEAAXXZ" = comdat any
-// GNU: $_ZN9BasicCaseIiE14to_be_exportedEv = comdat any
-// GNU: $_ZN11PolymorphicIiE14to_be_exportedEv = comdat any
-// GNU: $_ZN11PolymorphicIjE14to_be_exportedEv = comdat any
-// GNU: $_ZN9BasicCaseIiE25to_be_exported_explicitlyEv = comdat any
-// GNU: $_ZN9BasicCaseIiE18not_to_be_exportedEv = comdat any
-// GNU: $_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
-// GNU: $_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
-// GNU: $_ZN11PolymorphicIiE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN11PolymorphicIiE25to_be_exported_explicitlyEv = comdat any
-// GNU: $_ZN11PolymorphicIjE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN11PolymorphicIjE25to_be_exported_explicitlyEv = comdat any
-
-// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at H@@6B@")
-// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at I@@6B@")
-// MSC: @"??_7?$Polymorphic at H@@6B@" = dllexport unnamed_addr
-// MSC: @"??_7?$Polymorphic at I@@6B@" = unnamed_addr
-// GNU: @_ZTV11PolymorphicIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
-// GNU: @_ZTV11PolymorphicIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at H@@QEAAAEAU0@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$BasicCase at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseIiEaSEOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseIiE14to_be_exportedEv
-template struct __declspec(dllexport) BasicCase<int>;
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at H@@QEAAAEAU0@$$QEAU0@@Z"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateIiEaSEOS0_
-template struct ExportWholeTemplate<int>; // No dllexport here.
-// Don't provide explicit instantiation for ExportWholeTemplate<unsigned>.
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at H@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at H@@QEAAAEAU0@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA at XZ"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at H@@QEAA@$$QEAU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$Polymorphic at H@@UEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicIiEaSERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicIiEaSEOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2Ev
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1Ev
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2ERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1ERKS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC2EOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiEC1EOS0_
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicIiE14to_be_exportedEv
-template struct __declspec(dllexport) Polymorphic<int>;
-
-// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$Polymorphic at I@@UEAAXXZ"
-// GNU: define weak_odr dso_local{{.*}} void @_ZN11PolymorphicIjE14to_be_exportedEv
-template struct Polymorphic<unsigned int>;
-
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at I@@QEAAAEAU0 at AEBU0@@Z"
-// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at I@@QEAAAEAU0@$$QEAU0@@Z"
+// MSC: $"?to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
+// GNU: $_ZN9BasicCaseI13WithExportTagE14to_be_exportedEv = comdat any
+// GNU: $_ZN11PolymorphicI13WithExportTagE14to_be_exportedEv = comdat any
+// GNU: $_ZN11PolymorphicI9NoAttrTagE14to_be_exportedEv = comdat any
+// GNU: $_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN19ExportWholeTemplateI11ImplicitTagE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN11PolymorphicI13WithExportTagE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN11PolymorphicI13WithExportTagE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN11PolymorphicI9NoAttrTagE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN11PolymorphicI9NoAttrTagE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at UWithExportTag@@@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at UNoAttrTag@@@@6B@")
+// MSC: @"??_7?$Polymorphic at UWithExportTag@@@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
+// GNU: @_ZTV11PolymorphicI13WithExportTagE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat
+// GNU: @_ZTV11PolymorphicI9NoAttrTagE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at UWithExportTag@@@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$BasicCase at UWithExportTag@@@@QEAAAEAU0@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseI13WithExportTagEaSERKS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN9BasicCaseI13WithExportTagEaSEOS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseI13WithExportTagE14to_be_exportedEv
+template struct __declspec(dllexport) BasicCase<WithExportTag>;
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at UNoAttrTag@@@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at UNoAttrTag@@@@QEAAAEAU0@$$QEAU0@@Z"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateI9NoAttrTagEaSERKS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN19ExportWholeTemplateI9NoAttrTagEaSEOS1_
+template struct ExportWholeTemplate<NoAttrTag>;
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at UWithExportTag@@@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$Polymorphic at UWithExportTag@@@@QEAAAEAU0@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at UWithExportTag@@@@QEAA at XZ"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at UWithExportTag@@@@QEAA at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$Polymorphic at UWithExportTag@@@@QEAA@$$QEAU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicI13WithExportTagEaSERKS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN11PolymorphicI13WithExportTagEaSEOS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC2Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC1Ev
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC2ERKS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC1ERKS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC2EOS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagEC1EOS1_
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN11PolymorphicI13WithExportTagE14to_be_exportedEv
+template struct __declspec(dllexport) Polymorphic<WithExportTag>;
+
+// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU: define weak_odr dso_local{{.*}} void @_ZN11PolymorphicI9NoAttrTagE14to_be_exportedEv
+template struct Polymorphic<NoAttrTag>;
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at UImplicitTag@@@@QEAAAEAU0 at AEBU0@@Z"
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$ExportWholeTemplate at UImplicitTag@@@@QEAAAEAU0@$$QEAU0@@Z"
 
 void use() {
-  BasicCase<int> c;
+  BasicCase<WithExportTag> c;
 
-  // MSC: call void @"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseIiE25to_be_exported_explicitlyEv
+  // MSC: call void @"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv
   c.to_be_exported_explicitly(); // implicitly instantiated here
 
-  // MSC: call void @"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseIiE18not_to_be_exportedEv
+  // MSC: call void @"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv
   c.not_to_be_exported(); // implicitly instantiated here
 
-  ExportWholeTemplate<int> di;
+  ExportWholeTemplate<NoAttrTag> di;
 
-  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ"
-  // GNU: call void @_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN19ExportWholeTemplateI9NoAttrTagE44to_be_exported_iff_no_explicit_instantiationEv
   di.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  ExportWholeTemplate<unsigned> dj;
+  ExportWholeTemplate<ImplicitTag> dj;
 
-  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ"
-  // GNU: call void @_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN19ExportWholeTemplateI11ImplicitTagE44to_be_exported_iff_no_explicit_instantiationEv
   dj.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 }
 
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$BasicCase at H@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseIiE25to_be_exported_explicitlyEv
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$BasicCase at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseIiE18not_to_be_exportedEv
+// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at H@@QEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at I@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateIiE44to_be_exported_iff_no_explicit_instantiationEv
-// GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateIjE44to_be_exported_iff_no_explicit_instantiationEv
+// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE44to_be_exported_iff_no_explicit_instantiationEv
+// GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI11ImplicitTagE44to_be_exported_iff_no_explicit_instantiationEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at H@@UEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicIiE25to_be_exported_explicitlyEv
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE25to_be_exported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at I@@UEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicIjE25to_be_exported_explicitlyEv
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE18to_be_instantiatedEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI9NoAttrTagE25to_be_exported_explicitlyEv
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 8a00f66269b0f..cca933aba631b 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
@@ -16,6 +16,10 @@
 
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
+struct NoAttrTag {};
+struct WithImportTag {};
+struct ImplicitTag {};
+
 template <class T>
 struct BasicCase {
   // This will be instantiated explicitly as an imported function because it
@@ -55,11 +59,7 @@ struct Polymorphic {
   // functions regardless `exclude_from_explicit_instantiation`.
   // For the Itanium ABI: Emitting the VTable is suppressed by implicit
   // instantiation declaration so virtual member functions won't be instantiated.
-  EXCLUDE_ATTR explicit Polymorphic(int);
-
-  // This constructor doesn't trigger the instantiation of the VTable.
-  // In this case, declaration of virtual member functions are absent too.
-  explicit Polymorphic(long);
+  EXCLUDE_ATTR explicit Polymorphic();
 
   // The body of this shouldn't be emitted since instantiation is suppressed
   // by the explicit instantiation declaration.
@@ -74,98 +74,81 @@ struct Polymorphic {
 
 };
 
-template <class T> Polymorphic<T>::Polymorphic(int) {}
-template <class T> Polymorphic<T>::Polymorphic(long) {}
+template <class T> Polymorphic<T>::Polymorphic() {}
 template <class T> void Polymorphic<T>::to_be_imported() {}
 template <class T> void Polymorphic<T>::to_be_instantiated() {}
 
-// MSC: $"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ" = comdat any
-// GNU: $_ZN9BasicCaseIiE18not_to_be_importedEv = comdat any
-// GNU: $_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
-// GNU: @_ZTV11PolymorphicIiE = external dllimport unnamed_addr
-// GNU: @_ZTV11PolymorphicIjE = external unnamed_addr
+// MSC: $"?not_to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at UWithImportTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
+// GNU: $_ZN9BasicCaseI13WithImportTagE18not_to_be_importedEv = comdat any
+// GNU: $_ZN19ImportWholeTemplateI9NoAttrTagE44to_be_imported_iff_no_explicit_instantiationEv = comdat any
+// GNU: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr
+// GNU: @_ZTV11PolymorphicI9NoAttrTagE = external unnamed_addr
 
-// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$Polymorphic at H@@6B@")
-// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at I@@6B@")
-// MSC: @"??_S?$Polymorphic at H@@6B@" =
-// MSC: @"??_7?$Polymorphic at I@@6B@" =
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$Polymorphic at UWithImportTag@@@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at UNoAttrTag@@@@6B@")
+// MSC: @"??_S?$Polymorphic at UWithImportTag@@@@6B@" =
+// MSC: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" =
 
-extern template struct __declspec(dllimport) BasicCase<int>;
+extern template struct __declspec(dllimport) BasicCase<WithImportTag>;
 
-extern template struct ImportWholeTemplate<int>; // No dllimport here.
-// Don't provide explicit instantiation for ImportWholeTemplate<unsigned>.
+extern template struct ImportWholeTemplate<NoAttrTag>;
 
-extern template struct __declspec(dllimport) Polymorphic<int>;
-extern template struct Polymorphic<unsigned>;
-extern template struct __declspec(dllimport) Polymorphic<long int>;
-extern template struct Polymorphic<unsigned long int>;
+extern template struct __declspec(dllimport) Polymorphic<WithImportTag>;
+extern template struct Polymorphic<NoAttrTag>;
 
 void use() {
-  BasicCase<int> c;
+  BasicCase<WithImportTag> c;
 
-  // MSC: call void @"?to_be_imported@?$BasicCase at H@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseIiE14to_be_importedEv
+  // MSC: call void @"?to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithImportTagE14to_be_importedEv
   c.to_be_imported();
 
-  // MSC: call void @"?to_be_imported_explicitly@?$BasicCase at H@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseIiE25to_be_imported_explicitlyEv
+  // MSC: call void @"?to_be_imported_explicitly@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithImportTagE25to_be_imported_explicitlyEv
   c.to_be_imported_explicitly(); // implicitly instantiated here
 
-  // MSC: call void @"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseIiE18not_to_be_importedEv
+  // MSC: call void @"?not_to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithImportTagE18not_to_be_importedEv
   c.not_to_be_imported(); // implicitly instantiated here
 
-  ImportWholeTemplate<int> di;
+  ImportWholeTemplate<NoAttrTag> di;
 
-  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ"
-  // GNU: call void @_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN19ImportWholeTemplateI9NoAttrTagE44to_be_imported_iff_no_explicit_instantiationEv
   di.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  ImportWholeTemplate<unsigned> dj;
+  ImportWholeTemplate<ImplicitTag> dj;
 
-  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at I@@QEAAXXZ"
-  // GNU: call void @_ZN19ImportWholeTemplateIjE44to_be_imported_iff_no_explicit_instantiationEv
+  // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN19ImportWholeTemplateI11ImplicitTagE44to_be_imported_iff_no_explicit_instantiationEv
   dj.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here
 
-  Polymorphic<int> ei{1};
-
-  Polymorphic<unsigned> ej{1};
+  Polymorphic<WithImportTag> ei;
 
-  Polymorphic<long int> el{1L};
-
-  Polymorphic<unsigned long int> em{1L};
+  Polymorphic<NoAttrTag> ej;
 }
 
-// MSC: declare dllimport void @"?to_be_imported@?$BasicCase at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN9BasicCaseIiE14to_be_importedEv
-
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$BasicCase at H@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN9BasicCaseIiE25to_be_imported_explicitlyEv
+// MSC: declare dllimport void @"?to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14to_be_importedEv
 
-// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$BasicCase at H@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseIiE18not_to_be_importedEv
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN9BasicCaseI13WithImportTagE25to_be_imported_explicitlyEv
 
-// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at H@@QEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at I@@QEAAXXZ"
-// GNU: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateIiE44to_be_imported_iff_no_explicit_instantiationEv
-// GNU: declare dllimport void @_ZN19ImportWholeTemplateIjE44to_be_imported_iff_no_explicit_instantiationEv
+// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE18not_to_be_importedEv
 
-// MSC: declare dllimport noundef ptr @"??0?$Polymorphic at J@@QEAA at J@Z"
-// MSC: declare dso_local noundef ptr @"??0?$Polymorphic at K@@QEAA at J@Z"
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiEC1Ei
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjEC1Ei
-// GNU: declare dllimport void @_ZN11PolymorphicIlEC1El
-// GNU: declare dso_local void @_ZN11PolymorphicImEC1El
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIiEC2Ei
-// GNU: define linkonce_odr dso_local void @_ZN11PolymorphicIjEC2Ei
+// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at UNoAttrTag@@@@QEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$ImportWholeTemplate at UImplicitTag@@@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE44to_be_imported_iff_no_explicit_instantiationEv
+// GNU: declare dllimport void @_ZN19ImportWholeTemplateI11ImplicitTagE44to_be_imported_iff_no_explicit_instantiationEv
 
-// MSC: declare dllimport void @"?to_be_imported@?$Polymorphic at H@@UEAAXXZ"
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at H@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at H@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
 
-// MSC: declare dso_local void @"?to_be_imported@?$Polymorphic at I@@UEAAXXZ"
-// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at I@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at I@@UEAAXXZ"
+// MSC: declare dso_local void @"?to_be_imported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"

>From 5b7ec89f94a752f303724c27f53ab3c917302024 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 21 Feb 2026 20:21:29 +0900
Subject: [PATCH 20/20] avoid conflicts between check-not and filename

---
 ...t_instantiation.exclude_from_dllexport.cpp | 50 ++++++++-----------
 ...t_instantiation.exclude_from_dllimport.cpp | 30 +++++------
 2 files changed, 34 insertions(+), 46 deletions(-)

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 ed54167248ff9..df2762d1e8b5c 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
@@ -1,19 +1,13 @@
 // RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllexport
+// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=" dllexport"
 // RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=" dllexport"
 // RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=" dllexport"
 
 // Test that __declspec(dllexport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllexport explicitly.
 
-// Silence --implicit-check-not=dllexport.
-// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
-// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
-// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
-// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
-
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 struct NoAttrTag {};
@@ -28,7 +22,7 @@ struct BasicCase {
 
   // This will be instantiated implicitly as an exported function because it is
   // marked as dllexport explicitly.
-  EXCLUDE_ATTR __declspec(dllexport) void to_be_exported_explicitly();
+  EXCLUDE_ATTR __declspec(dllexport) void to_be_memberwise_exported();
 
   // This will be instantiated implicitly but won't be exported.
   EXCLUDE_ATTR void not_to_be_exported();
@@ -39,7 +33,7 @@ struct BasicCase {
 
 // Member functions can't be inlined since clang in MinGW mode doesn't export/import them that are inlined.
 template <class T> void BasicCase<T>::to_be_exported() {}
-template <class T> void BasicCase<T>::to_be_exported_explicitly() {}
+template <class T> void BasicCase<T>::to_be_memberwise_exported() {}
 template <class T> void BasicCase<T>::not_to_be_exported() {}
 template <class T> void BasicCase<T>::not_to_be_instantiated() {}
 
@@ -64,35 +58,35 @@ struct Polymorphic {
   EXCLUDE_ATTR virtual void to_be_instantiated();
 
   // This too, but will be exported by the member attribute.
-  EXCLUDE_ATTR __declspec(dllexport) virtual void to_be_exported_explicitly();
+  EXCLUDE_ATTR __declspec(dllexport) virtual void to_be_memberwise_exported();
 };
 
 template <class T> void Polymorphic<T>::to_be_exported() {}
 template <class T> void Polymorphic<T>::to_be_instantiated() {}
-template <class T> void Polymorphic<T>::to_be_exported_explicitly() {}
+template <class T> void Polymorphic<T>::to_be_memberwise_exported() {}
 
 // MSC: $"?to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_exported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_memberwise_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
 // MSC: $"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UNoAttrTag@@@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$ExportWholeTemplate at UImplicitTag@@@@QEAAXXZ" = comdat any
 // MSC: $"?to_be_instantiated@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_memberwise_exported@?$Polymorphic at UWithExportTag@@@@UEAAXXZ" = comdat any
 // MSC: $"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
-// MSC: $"?to_be_exported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_memberwise_exported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ" = comdat any
 // GNU: $_ZN9BasicCaseI13WithExportTagE14to_be_exportedEv = comdat any
 // GNU: $_ZN11PolymorphicI13WithExportTagE14to_be_exportedEv = comdat any
 // GNU: $_ZN11PolymorphicI9NoAttrTagE14to_be_exportedEv = comdat any
-// GNU: $_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN9BasicCaseI13WithExportTagE25to_be_memberwise_exportedEv = comdat any
 // GNU: $_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv = comdat any
 // GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
 // GNU: $_ZN19ExportWholeTemplateI11ImplicitTagE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
 // GNU: $_ZN11PolymorphicI13WithExportTagE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN11PolymorphicI13WithExportTagE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN11PolymorphicI13WithExportTagE25to_be_memberwise_exportedEv = comdat any
 // GNU: $_ZN11PolymorphicI9NoAttrTagE18to_be_instantiatedEv = comdat any
-// GNU: $_ZN11PolymorphicI9NoAttrTagE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN11PolymorphicI9NoAttrTagE25to_be_memberwise_exportedEv = comdat any
 
 // MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at UWithExportTag@@@@6B@")
 // MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$Polymorphic at UNoAttrTag@@@@6B@")
@@ -142,9 +136,9 @@ template struct Polymorphic<NoAttrTag>;
 void use() {
   BasicCase<WithExportTag> c;
 
-  // MSC: call void @"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv
-  c.to_be_exported_explicitly(); // implicitly instantiated here
+  // MSC: call void @"?to_be_memberwise_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithExportTagE25to_be_memberwise_exportedEv
+  c.to_be_memberwise_exported(); // implicitly instantiated here
 
   // MSC: call void @"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
   // GNU: call void @_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv
@@ -163,8 +157,8 @@ void use() {
   dj.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here
 }
 
-// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
-// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseI13WithExportTagE25to_be_exported_explicitlyEv
+// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_memberwise_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN9BasicCaseI13WithExportTagE25to_be_memberwise_exportedEv
 
 // MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE18not_to_be_exportedEv
@@ -175,11 +169,11 @@ void use() {
 // GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI11ImplicitTagE44to_be_exported_iff_no_explicit_instantiationEv
 
 // MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_memberwise_exported@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE25to_be_exported_explicitlyEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE25to_be_memberwise_exportedEv
 
 // MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
-// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// MSC: define weak_odr dso_local dllexport void @"?to_be_memberwise_exported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE18to_be_instantiatedEv
-// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI9NoAttrTagE25to_be_exported_explicitlyEv
+// GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI9NoAttrTagE25to_be_memberwise_exportedEv
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 cca933aba631b..4736c35c32260 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
@@ -1,19 +1,13 @@
 // RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllimport
+// RUN:     FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=" dllimport"
 // RUN: %clang_cc1 -triple x86_64-mingw                 -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=" dllimport"
 // RUN: %clang_cc1 -triple x86_64-cygwin                -emit-llvm -o - %s | \
-// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport
+// RUN:     FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=" dllimport"
 
 // Test that __declspec(dllimport) doesn't instantiate entities marked with
 // the exclude_from_explicit_instantiation attribute unless marked as dllimport explicitly.
 
-// Silence --implicit-check-not=dllimport.
-// MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp
-// MSC: source_filename = {{.*}}exclude_from_dllimport.cpp
-// GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp
-// GNU: source_filename = {{.*}}exclude_from_dllimport.cpp
-
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
 struct NoAttrTag {};
@@ -28,7 +22,7 @@ struct BasicCase {
 
   // This will be instantiated implicitly as an imported function because it is
   // marked as dllimport explicitly.
-  EXCLUDE_ATTR __declspec(dllimport) void to_be_imported_explicitly();
+  EXCLUDE_ATTR __declspec(dllimport) void to_be_memberwise_imported();
 
   // This will be instantiated implicitly but won't be imported.
   EXCLUDE_ATTR void not_to_be_imported();
@@ -70,7 +64,7 @@ struct Polymorphic {
   EXCLUDE_ATTR virtual void to_be_instantiated();
 
   // The body of this shouldn't be emitted since that comes from an external DLL.
-  EXCLUDE_ATTR __declspec(dllimport) virtual void to_be_imported_explicitly();
+  EXCLUDE_ATTR __declspec(dllimport) virtual void to_be_memberwise_imported();
 
 };
 
@@ -106,9 +100,9 @@ void use() {
   // GNU: call void @_ZN9BasicCaseI13WithImportTagE14to_be_importedEv
   c.to_be_imported();
 
-  // MSC: call void @"?to_be_imported_explicitly@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
-  // GNU: call void @_ZN9BasicCaseI13WithImportTagE25to_be_imported_explicitlyEv
-  c.to_be_imported_explicitly(); // implicitly instantiated here
+  // MSC: call void @"?to_be_memberwise_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+  // GNU: call void @_ZN9BasicCaseI13WithImportTagE25to_be_memberwise_importedEv
+  c.to_be_memberwise_imported(); // implicitly instantiated here
 
   // MSC: call void @"?not_to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
   // GNU: call void @_ZN9BasicCaseI13WithImportTagE18not_to_be_importedEv
@@ -134,8 +128,8 @@ void use() {
 // MSC: declare dllimport void @"?to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
 // GNU: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14to_be_importedEv
 
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
-// GNU: declare dllimport void @_ZN9BasicCaseI13WithImportTagE25to_be_imported_explicitlyEv
+// MSC: declare dllimport void @"?to_be_memberwise_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN9BasicCaseI13WithImportTagE25to_be_memberwise_importedEv
 
 // MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
 // GNU: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE18not_to_be_importedEv
@@ -147,8 +141,8 @@ void use() {
 
 // MSC: declare dllimport void @"?to_be_imported@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
 // MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_memberwise_imported@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
 
 // MSC: declare dso_local void @"?to_be_imported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
 // MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
-// MSC: declare dllimport void @"?to_be_imported_explicitly@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// MSC: declare dllimport void @"?to_be_memberwise_imported@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"



More information about the cfe-commits mailing list