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

>From 996b78b19a6657ef0cf9e40d23c125b779fddb4d Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Sat, 28 Mar 2026 12:34:19 +0900
Subject: [PATCH 1/4] pretest

---
 clang/test/SemaCXX/dllexport.cpp | 50 ++++++++++++++++++++++++++++++++
 clang/test/SemaCXX/dllimport.cpp | 45 ++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp
index 70e7f1398ad05..24f39d813b498 100644
--- a/clang/test/SemaCXX/dllexport.cpp
+++ b/clang/test/SemaCXX/dllexport.cpp
@@ -1063,6 +1063,56 @@ template<typename T> __declspec(dllexport) constexpr int 
CTMR<T>::ConstexprField
 // dllexport.
 template <> void ExportClassTmplMembers<int>::normalDecl() = delete; // 
non-gnu-error {{attribute 'dllexport' cannot be applied to a deleted function}}
 
+struct InstTrig {
+    struct Spec;
+    struct Impl;
+    struct Decl;
+};
+template<bool InstDef, typename... Triggers>
+struct ClassTmplSpecializedMember { // gnu-note 5 {{'dllexport' attribute is 
missing on previous declaration}}
+  void specializedMember1();
+  void specializedMember2();
+  void instantiatedMember1();
+  void instantiatedMember2();
+  void member() {}
+};
+
+template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1();
+extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec>; // non-gnu-warning{{explicit instantiation declaration should 
not be 'dllexport'}} \
+                                                                               
                    non-gnu-note{{attribute is here}}
+template <> void ClassTmplSpecializedMember<true, 
InstTrig::Spec>::specializedMember1();
+template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute ignored on 
explicit instantiation definition}}
+
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
+extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Impl>; // non-gnu-warning{{explicit instantiation declaration should 
not be 'dllexport'}} \
+                                                                               
                    non-gnu-note{{attribute is here}}
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
+template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Impl>;         // gnu-warning{{'dllexport' attribute ignored on 
explicit instantiation definition}}
+
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
+extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Spec>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
+                                                                               
                                    non-gnu-note{{attribute is here}}
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
+template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
+
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
+extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Impl>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
+                                                                               
                                    non-gnu-note{{attribute is here}}
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
+template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Impl>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
+
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+template <> void ClassTmplSpecializedMember<false, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
+extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Impl, InstTrig::Spec>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
+                                                                               
                                    non-gnu-note{{attribute is here}}
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+template <> void ClassTmplSpecializedMember<true, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
+template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Impl, InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
+
 
 
//===----------------------------------------------------------------------===//
 // Class template member templates
diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp
index deb0574cb5e68..aa8c823bfe85c 100644
--- a/clang/test/SemaCXX/dllimport.cpp
+++ b/clang/test/SemaCXX/dllimport.cpp
@@ -999,6 +999,51 @@ template<> void ClassTmpl<int>::importedStatic() {} // 
non-gnu-error{{cannot def
 
 template <> void ImportClassTmplMembers<int>::normalDecl() = delete; // 
non-gnu-error{{cannot define non-inline dllimport template specialization}} \
                                                                         
non-gnu-error{{attribute 'dllimport' cannot be applied to a deleted function}}
+struct InstTrig {
+    struct Spec;
+    struct Impl;
+    struct Decl;
+};
+template<bool InstDef, typename... Triggers>
+struct ClassTmplSpecializedMember {
+  void specializedMember1();
+  void specializedMember2();
+  void instantiatedMember1();
+  void instantiatedMember2();
+  void member() {}
+};
+
+template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1();
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec>;
+template <> void ClassTmplSpecializedMember<true, 
InstTrig::Spec>::specializedMember1();
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec>;
+
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl>;
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl>;
+
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Spec>;
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Spec>;
+
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Impl>;
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Impl>;
+
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+template <> void ClassTmplSpecializedMember<false, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl, InstTrig::Spec>;
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+template <> void ClassTmplSpecializedMember<true, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl, InstTrig::Spec>;
+
 
 
//===----------------------------------------------------------------------===//
 // Class template member templates

>From 9a13f16300c0021969b0532062dffc478dbb22d6 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Sun, 15 Mar 2026 18:19:23 +0900
Subject: [PATCH 2/4] [Clang] Warn about ignored dllimport on explicit
 instantiations

Diagnose about a non-effective dllimport attribute on an explicit instantiation 
declaration for a specialization which
was already (implicitly) instantiated somewhere, rather than ignoring it 
silently.

related to #21132
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 ++
 clang/lib/Sema/SemaTemplate.cpp               | 99 ++++++++++++-------
 2 files changed, 69 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9bd0a526654c7..96f390226bec5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3874,6 +3874,9 @@ def warn_dllimport_dropped_from_inline_function : Warning<
 def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts 
with"
   " exception specification; attribute ignored">,
   InGroup<IgnoredAttributes>;
+def warn_dllattr_ignored_already_instantiated : Warning<
+  "%0 attribute ignored; class template is already instantiated">,
+  InGroup<IgnoredAttributes>;
 def warn_dllattr_ignored_exclusion_takes_precedence : Warning<
   "%0 attribute ignored; %1 takes precedence">,
   InGroup<IgnoredAttributes>;
@@ -3997,6 +4000,9 @@ def err_attribute_dllimport_static_field_definition : 
Error<
 def warn_attribute_dllimport_static_field_definition : Warning<
   "definition of dllimport static field">,
   InGroup<DiagGroup<"dllimport-static-field-def">>;
+def warn_attribute_dllimport_explicit_instantiation_def : Warning<
+  "'dllimport' attribute ignored on explicit instantiation definition">,
+  InGroup<IgnoredAttributes>;
 def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
   "explicit instantiation declaration should not be 'dllexport'">,
   InGroup<DllexportExplicitInstantiationDecl>;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b8b0c71894daa..9db77f8387337 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10294,23 +10294,32 @@ DeclResult Sema::ActOnExplicitInstantiation(
                                        ? TSK_ExplicitInstantiationDefinition
                                        : TSK_ExplicitInstantiationDeclaration;
 
+  bool DLLAttrAffected = false;
+  const ParsedAttr *AttachedExportAttr = nullptr;
+  const ParsedAttr *AttachedImportAttr = nullptr;
+  for (const ParsedAttr &AL : Attr) {
+    if (AL.getKind() == ParsedAttr::AT_DLLExport)
+      AttachedExportAttr = &AL;
+    else if (AL.getKind() == ParsedAttr::AT_DLLImport)
+      AttachedImportAttr = &AL;
+  }
+
   if (TSK == TSK_ExplicitInstantiationDeclaration &&
       !Context.getTargetInfo().getTriple().isOSCygMing()) {
     // Check for dllexport class template instantiation declarations,
     // except for MinGW mode.
-    for (const ParsedAttr &AL : Attr) {
-      if (AL.getKind() == ParsedAttr::AT_DLLExport) {
-        Diag(ExternLoc,
-             diag::warn_attribute_dllexport_explicit_instantiation_decl);
-        Diag(AL.getLoc(), diag::note_attribute);
-        break;
-      }
+    if (AttachedExportAttr) {
+      Diag(ExternLoc,
+           diag::warn_attribute_dllexport_explicit_instantiation_decl);
+      Diag(AttachedExportAttr->getLoc(), diag::note_attribute);
+      DLLAttrAffected = true;
     }
 
     if (auto *A = ClassTemplate->getTemplatedDecl()->getAttr<DLLExportAttr>()) 
{
       Diag(ExternLoc,
            diag::warn_attribute_dllexport_explicit_instantiation_decl);
       Diag(A->getLocation(), diag::note_attribute);
+      DLLAttrAffected = true;
     }
   }
 
@@ -10318,20 +10327,11 @@ DeclResult Sema::ActOnExplicitInstantiation(
   // instantiation declarations for most purposes.
   bool DLLImportExplicitInstantiationDef = false;
   if (TSK == TSK_ExplicitInstantiationDefinition &&
-      Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+      Context.getTargetInfo().shouldDLLImportComdatSymbols()) {
     // Check for dllimport class template instantiation definitions.
     bool DLLImport =
         ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>();
-    for (const ParsedAttr &AL : Attr) {
-      if (AL.getKind() == ParsedAttr::AT_DLLImport)
-        DLLImport = true;
-      if (AL.getKind() == ParsedAttr::AT_DLLExport) {
-        // dllexport trumps dllimport here.
-        DLLImport = false;
-        break;
-      }
-    }
-    if (DLLImport) {
+    if ((DLLImport || AttachedImportAttr) && !AttachedExportAttr) {
       TSK = TSK_ExplicitInstantiationDeclaration;
       DLLImportExplicitInstantiationDef = true;
     }
@@ -10363,28 +10363,30 @@ DeclResult Sema::ActOnExplicitInstantiation(
       Context.getTargetInfo().getTriple().isOSCygMing()) {
     // Check for dllexport class template instantiation definitions in MinGW
     // mode, if a previous declaration of the instantiation was seen.
-    for (const ParsedAttr &AL : Attr) {
-      if (AL.getKind() == ParsedAttr::AT_DLLExport) {
-        if (PrevDecl->hasAttr<DLLExportAttr>()) {
-          Diag(AL.getLoc(), diag::warn_attr_dllexport_explicit_inst_def);
-        } else {
-          Diag(AL.getLoc(),
-               diag::warn_attr_dllexport_explicit_inst_def_mismatch);
-          Diag(PrevDecl->getLocation(), 
diag::note_prev_decl_missing_dllexport);
-        }
-        break;
+    if (AttachedExportAttr) {
+      if (PrevDecl->hasAttr<DLLExportAttr>()) {
+        Diag(AttachedExportAttr->getLoc(),
+             diag::warn_attr_dllexport_explicit_inst_def);
+      } else {
+        Diag(AttachedExportAttr->getLoc(),
+             diag::warn_attr_dllexport_explicit_inst_def_mismatch);
+        Diag(PrevDecl->getLocation(), diag::note_prev_decl_missing_dllexport);
       }
+      DLLAttrAffected = true;
+    } else if (AttachedImportAttr) {
+      Diag(AttachedImportAttr->getLoc(),
+           diag::warn_attribute_dllimport_explicit_instantiation_def);
+      DLLAttrAffected = true;
     }
   }
 
   if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl &&
       !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() &&
-      llvm::none_of(Attr, [](const ParsedAttr &AL) {
-        return AL.getKind() == ParsedAttr::AT_DLLExport;
-      })) {
+      !AttachedExportAttr) {
     if (const auto *DEA = PrevDecl->getAttr<DLLExportOnDeclAttr>()) {
       Diag(TemplateLoc, diag::warn_dllexport_on_decl_ignored);
       Diag(DEA->getLoc(), diag::note_dllexport_on_decl);
+      DLLAttrAffected = true;
     }
   }
 
@@ -10456,7 +10458,10 @@ DeclResult Sema::ActOnExplicitInstantiation(
   Specialization->setTemplateKeywordLoc(TemplateLoc);
   Specialization->setBraceRange(SourceRange());
 
-  bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
+  bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>() ||
+                               (PrevDecl && 
PrevDecl->hasAttr<DLLExportAttr>());
+  bool PreviouslyDLLImported = Specialization->hasAttr<DLLImportAttr>() ||
+                               (PrevDecl && 
PrevDecl->hasAttr<DLLImportAttr>());
   ProcessDeclAttributeList(S, Specialization, Attr);
   ProcessAPINotes(Specialization);
 
@@ -10492,11 +10497,12 @@ DeclResult Sema::ActOnExplicitInstantiation(
   ClassTemplateSpecializationDecl *Def
     = cast_or_null<ClassTemplateSpecializationDecl>(
                                               Specialization->getDefinition());
-  if (!Def)
+  if (!Def) {
     InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, 
TSK,
                                            /*Complain=*/true,
                                            CTAI.StrictPackMatch);
-  else if (TSK == TSK_ExplicitInstantiationDefinition) {
+    DLLAttrAffected = true;
+  } else if (TSK == TSK_ExplicitInstantiationDefinition) {
     MarkVTableUsed(TemplateNameLoc, Specialization, true);
     Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());
   }
@@ -10524,13 +10530,16 @@ DeclResult Sema::ActOnExplicitInstantiation(
         A->setInherited(true);
         Def->addAttr(A);
         dllExportImportClassTemplateSpecialization(*this, Def);
+        DLLAttrAffected = true;
       }
     }
 
     // Fix a TSK_ImplicitInstantiation followed by a
     // TSK_ExplicitInstantiationDefinition
-    bool NewlyDLLExported =
-        !PreviouslyDLLExported && Specialization->hasAttr<DLLExportAttr>();
+    bool NewlyDLLExported = !PreviouslyDLLExported && AttachedExportAttr &&
+                            Specialization->hasAttr<DLLExportAttr>();
+    bool NewlyDLLImported = !PreviouslyDLLImported && AttachedImportAttr &&
+                            Specialization->hasAttr<DLLImportAttr>();
     if (Old_TSK == TSK_ImplicitInstantiation && NewlyDLLExported &&
         Context.getTargetInfo().shouldDLLImportComdatSymbols()) {
       // An explicit instantiation definition can add a dll attribute to a
@@ -10548,6 +10557,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
       assert(Def == Specialization &&
              "Def and Specialization should match for implicit instantiation");
       dllExportImportClassTemplateSpecialization(*this, Def);
+      DLLAttrAffected = true;
     }
 
     // In MinGW mode, export the template instantiation if the declaration
@@ -10556,6 +10566,23 @@ DeclResult Sema::ActOnExplicitInstantiation(
         Context.getTargetInfo().getTriple().isOSCygMing() &&
         PrevDecl->hasAttr<DLLExportAttr>()) {
       dllExportImportClassTemplateSpecialization(*this, Def);
+      DLLAttrAffected = true;
+    }
+
+    if (!DLLAttrAffected && (NewlyDLLExported || NewlyDLLImported)) {
+      if (Context.getTargetInfo().getTriple().isOSCygMing() &&
+          TSK == TSK_ExplicitInstantiationDeclaration && NewlyDLLImported) {
+        // In MinGW mode, all undefined symbols are also searched from DLLs
+        // even if they were not declared with dllimport, so doesn't warn
+        // about ignoring dllimport.
+      } else {
+        const ParsedAttr *A =
+            AttachedExportAttr ? AttachedExportAttr : AttachedImportAttr;
+        Diag(A->getLoc(), diag::warn_dllattr_ignored_already_instantiated) << 
A;
+        Diag(Def->getPointOfInstantiation(),
+             diag::note_instantiation_required_here)
+            << /*implicit|explicit=*/0;
+      }
     }
 
     // Set the template specialization kind. Make sure it is set before

>From 8244a27297d6ab5843072a90e2ab342b6b4c6f96 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Thu, 19 Mar 2026 21:47:26 +0900
Subject: [PATCH 3/4] update test

---
 clang/test/SemaCXX/dllexport.cpp | 25 +++++++++-------
 clang/test/SemaCXX/dllimport.cpp | 49 ++++++++++++++++++--------------
 2 files changed, 42 insertions(+), 32 deletions(-)

diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp
index 24f39d813b498..51c37e0d53eda 100644
--- a/clang/test/SemaCXX/dllexport.cpp
+++ b/clang/test/SemaCXX/dllexport.cpp
@@ -1077,38 +1077,43 @@ struct ClassTmplSpecializedMember { // gnu-note 5 
{{'dllexport' attribute is mis
   void member() {}
 };
 
-template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1();       // gnu-note{{implicit 
instantiation first required here}}
 extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec>; // non-gnu-warning{{explicit instantiation declaration should 
not be 'dllexport'}} \
-                                                                               
                    non-gnu-note{{attribute is here}}
+                                                                               
                    non-gnu-note{{attribute is here}} \
+                                                                               
                    gnu-warning{{'dllexport' attribute ignored; class template 
is already instantiated}}
 template <> void ClassTmplSpecializedMember<true, 
InstTrig::Spec>::specializedMember1();
 template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute ignored on 
explicit instantiation definition}}
 
-void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }  // gnu-note{{implicit instantiation first required 
here}}
 extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Impl>; // non-gnu-warning{{explicit instantiation declaration should 
not be 'dllexport'}} \
-                                                                               
                    non-gnu-note{{attribute is here}}
+                                                                               
                    non-gnu-note{{attribute is here}} \
+                                                                               
                    gnu-warning{{'dllexport' attribute ignored; class template 
is already instantiated}}
 void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
 template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Impl>;         // gnu-warning{{'dllexport' attribute ignored on 
explicit instantiation definition}}
 
-template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();       // gnu-note{{implicit 
instantiation first required here}}
 template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
 extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Spec>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
-                                                                               
                                    non-gnu-note{{attribute is here}}
+                                                                               
                                    non-gnu-note{{attribute is here}} \
+                                                                               
                                    gnu-warning{{'dllexport' attribute ignored; 
class template is already instantiated}}
 template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
 template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
 template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
 
-template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();       // gnu-note{{implicit 
instantiation first required here}}
 void anchor(ClassTmplSpecializedMember<false, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
 extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Impl>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
-                                                                               
                                    non-gnu-note{{attribute is here}}
+                                                                               
                                    non-gnu-note{{attribute is here}} \
+                                                                               
                                    gnu-warning{{'dllexport' attribute ignored; 
class template is already instantiated}}
 template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
 void anchor(ClassTmplSpecializedMember<true, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
 template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Impl>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
 
-void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }  // gnu-note{{implicit instantiation first 
required here}}
 template <> void ClassTmplSpecializedMember<false, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
 extern template struct __declspec(dllexport) ClassTmplSpecializedMember<false, 
InstTrig::Impl, InstTrig::Spec>; // non-gnu-warning{{explicit instantiation 
declaration should not be 'dllexport'}} \
-                                                                               
                                    non-gnu-note{{attribute is here}}
+                                                                               
                                    non-gnu-note{{attribute is here}} \
+                                                                               
                                    gnu-warning{{'dllexport' attribute ignored; 
class template is already instantiated}}
 void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
 template <> void ClassTmplSpecializedMember<true, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
 template struct __declspec(dllexport) ClassTmplSpecializedMember<true, 
InstTrig::Impl, InstTrig::Spec>;         // gnu-warning{{'dllexport' attribute 
ignored on explicit instantiation definition}}
diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp
index aa8c823bfe85c..c0266be95cd62 100644
--- a/clang/test/SemaCXX/dllimport.cpp
+++ b/clang/test/SemaCXX/dllimport.cpp
@@ -1013,36 +1013,41 @@ struct ClassTmplSpecializedMember {
   void member() {}
 };
 
-template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1();
-extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec>;
-template <> void ClassTmplSpecializedMember<true, 
InstTrig::Spec>::specializedMember1();
-template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec>;
-
-void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
-extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl>;
-void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl> &x) { 
x.instantiatedMember1(); }
-template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl>;
-
-template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, 
InstTrig::Spec>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute ignored; class 
template is already instantiated}}
+template <> void ClassTmplSpecializedMember<true, 
InstTrig::Spec>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute ignored; class 
template is already instantiated}} \
+                                                                               
            gnu-warning{{'dllimport' attribute ignored on explicit 
instantiation definition}}
+
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl> &x) { 
x.instantiatedMember1(); } // non-gnu-note{{implicit instantiation first 
required here}}
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl>; // non-gnu-warning{{'dllimport' attribute ignored; class 
template is already instantiated}}
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl> &x) { 
x.instantiatedMember1(); } // non-gnu-note{{implicit instantiation first 
required here}}
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl>; // non-gnu-warning{{'dllimport' attribute ignored; class 
template is already instantiated}} \
+                                                                               
            gnu-warning{{'dllimport' attribute ignored on explicit 
instantiation definition}}
+
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
 template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
-extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Spec>;
-template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1();
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}}
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
 template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Spec>::specializedMember2();
-template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Spec>;
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}} \
+                                                                               
                            gnu-warning{{'dllimport' attribute ignored on 
explicit instantiation definition}}
 
-template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+template <> void ClassTmplSpecializedMember<false, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
 void anchor(ClassTmplSpecializedMember<false, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
-extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Impl>;
-template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1();
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Spec, InstTrig::Impl>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}}
+template <> void ClassTmplSpecializedMember<true, InstTrig::Spec, 
InstTrig::Impl>::specializedMember1(); // non-gnu-note{{implicit instantiation 
first required here}}
 void anchor(ClassTmplSpecializedMember<true, InstTrig::Spec, InstTrig::Impl> 
&x) { x.instantiatedMember1(); }
-template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Impl>;
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Spec, InstTrig::Impl>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}} \
+                                                                               
                            gnu-warning{{'dllimport' attribute ignored on 
explicit instantiation definition}}
 
-void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+void anchor(ClassTmplSpecializedMember<false, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); } // non-gnu-note{{implicit instantiation first 
required here}}
 template <> void ClassTmplSpecializedMember<false, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
-extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl, InstTrig::Spec>;
-void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); }
+extern template struct __declspec(dllimport) ClassTmplSpecializedMember<false, 
InstTrig::Impl, InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}}
+void anchor(ClassTmplSpecializedMember<true, InstTrig::Impl, InstTrig::Spec> 
&x) { x.instantiatedMember1(); } // non-gnu-note{{implicit instantiation first 
required here}}
 template <> void ClassTmplSpecializedMember<true, InstTrig::Impl, 
InstTrig::Spec>::specializedMember1();
-template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl, InstTrig::Spec>;
+template struct __declspec(dllimport) ClassTmplSpecializedMember<true, 
InstTrig::Impl, InstTrig::Spec>; // non-gnu-warning{{'dllimport' attribute 
ignored; class template is already instantiated}} \
+                                                                               
                            gnu-warning{{'dllimport' attribute ignored on 
explicit instantiation definition}}
 
 
 
//===----------------------------------------------------------------------===//

>From 1213a7c256c8eb4a896a634e7e8f54c2cddffa8a Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Wed, 9 Sep 2026 06:14:01 +0900
Subject: [PATCH 4/4] restore a comment

---
 clang/lib/Sema/SemaTemplate.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9db77f8387337..50ff56ff7811e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10331,6 +10331,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
     // Check for dllimport class template instantiation definitions.
     bool DLLImport =
         ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>();
+    // dllexport trumps dllimport.
     if ((DLLImport || AttachedImportAttr) && !AttachedExportAttr) {
       TSK = TSK_ExplicitInstantiationDeclaration;
       DLLImportExplicitInstantiationDef = true;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to