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

>From 7dee8e88b0ffad0e1226fdacbfd36899dd0bda16 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Thu, 26 Feb 2026 21:49:40 +0900
Subject: [PATCH 1/4] [Clang] Drop dllexport/dllimport if conflicted with
 `exclude_from_explicit_instantiation`

Drop `dllexport` and `dllimport` attributes from a entity that is declared with
the `exclude_from_explicit_instantiation` attribute. Despite its name, the
exclude attribute takes precedence over the DLL attributes, even if the entity
is implicitly instantiated.

This makes the semantics of the attribute simpler -- "excluded members are never
DLL-exported/imported".

In a non-template context, the exclude attribute is already dropped, so the DLL
attributes take precedence.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +
 clang/lib/Sema/SemaDeclCXX.cpp                |  9 ++
 ..._explicit_instantiation.ignore-dllattr.cpp | 98 +++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 
clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8a3b9de19ad32..3bded7c6f78e7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3784,6 +3784,9 @@ def 
warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
 def warn_redeclaration_without_import_attribute : Warning<
   "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">,
   InGroup<MicrosoftInconsistentDllImport>;
+def warn_dllattr_ignored_exclusion_takes_precedence : Warning<
+  "%0 attribute ignored; %1 takes precedence">,
+  InGroup<IgnoredAttributes>;
 def warn_dllimport_dropped_from_inline_function : Warning<
   "%q0 redeclared inline; %1 attribute ignored">,
   InGroup<IgnoredAttributes>;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5837ecd6b9163..ed6da8bd317f6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7229,6 +7229,15 @@ void Sema::CheckCompletedCXXClass(Scope *S, 
CXXRecordDecl *Record) {
   bool HasMethodWithOverrideControl = false,
        HasOverridingMethodWithoutOverrideControl = false;
   for (auto *D : Record->decls()) {
+    if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) {
+      if (auto *DA = getDLLAttr(D)) {
+        Diag(DA->getRange().getBegin(),
+             diag::warn_dllattr_ignored_exclusion_takes_precedence)
+            << *DA << EA;
+        D->dropAttrs<DLLExportAttr, DLLImportAttr>();
+      }
+    }
+
     if (auto *M = dyn_cast<CXXMethodDecl>(D)) {
       // FIXME: We could do this check for dependent types with non-dependent
       // bases.
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
new file mode 100644
index 0000000000000..af15ed9f34688
--- /dev/null
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -fsyntax-only -verify 
%s
+// RUN: %clang_cc1 -triple x86_64-mingw                 -fsyntax-only -verify 
%s
+// RUN: %clang_cc1 -triple x86_64-cygwin                -fsyntax-only -verify 
%s
+
+// Test that memberwise dllexport and dllimport are warned if the
+// exclude_from_explicit_instantiation attribute is attached.
+
+#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
+
+template <class T>
+struct C {
+  EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported();
+// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported();
+// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported;
+// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported;
+// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {};
+// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {};
+// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+
+  // No warnings here since nested_excluded is not instantiated.
+  struct EXCLUDE_ATTR nested_excluded {
+    __declspec(dllexport) void fn_exported();
+    __declspec(dllimport) void fn_imported();
+  };
+  // This too. nested_exported is not instantiated.
+  struct __declspec(dllexport) nested_exported {
+    EXCLUDE_ATTR void fn_excluded();
+    EXCLUDE_ATTR static int var_excluded;
+  };
+  // The same. nested_imported is not instantiated.
+  struct __declspec(dllimport) nested_imported {
+    EXCLUDE_ATTR void fn_excluded();
+    EXCLUDE_ATTR static int var_excluded;
+  };
+
+  struct nested {
+    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported();
+    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported();
+    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported;
+    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported;
+    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  };
+};
+
+// Test that class-level dll attributes doesn't cause a warning on an excluded 
member.
+template <class T>
+struct __declspec(dllexport) DE {
+  EXCLUDE_ATTR void fn_excluded();
+};
+template struct DE<int>;
+
+template <class T>
+struct __declspec(dllimport) DI {
+  EXCLUDE_ATTR void fn_excluded();
+};
+template struct DI<int>;
+
+// Test that dll attributes on explicit instantiation doesn't cause a warning 
on
+// an excluded member.
+// However, a non-template nested type may be warned on an excluded member by
+// its dll attribute.
+template <class T>
+struct E {
+  EXCLUDE_ATTR void fn_excluded();
+  struct EXCLUDE_ATTR nested_excluded {
+    __declspec(dllexport) void fn_exported();
+    __declspec(dllimport) void fn_imported();
+  };
+
+  struct __declspec(dllexport) nested_exported_1 {
+    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR void fn_excluded();
+  };
+  struct __declspec(dllimport) nested_imported_1 {
+    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR void fn_excluded();
+  };
+
+  // Make sure that any warning isn't emitted if the nested type has no 
excluded members.
+  struct __declspec(dllexport) nested_exported_2 {
+    void fn();
+  };
+  struct __declspec(dllimport) nested_imported_2 {
+    void fn();
+  };
+};
+extern template struct __declspec(dllimport) E<long>;
+template struct __declspec(dllexport) E<int>;
+// expected-note@-1{{in instantiation of member class 
'E<int>::nested_exported_1' requested here}}
+// expected-note@-2{{in instantiation of member class 
'E<int>::nested_imported_1' requested here}}

>From e207b7cf7bff5cbcadac9160b1b8ef630b3839b4 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Fri, 27 Feb 2026 19:19:54 +0900
Subject: [PATCH 2/4] unfold

---
 ..._explicit_instantiation.ignore-dllattr.cpp | 36 +++++++------------
 1 file changed, 12 insertions(+), 24 deletions(-)

diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
index af15ed9f34688..1714d387d2bec 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
@@ -9,18 +9,12 @@
 
 template <class T>
 struct C {
-  EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported();
-// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-  EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported();
-// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-  EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported;
-// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-  EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported;
-// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-  struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {};
-// expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-  struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {};
-// expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
 
   // No warnings here since nested_excluded is not instantiated.
   struct EXCLUDE_ATTR nested_excluded {
@@ -39,14 +33,10 @@ struct C {
   };
 
   struct nested {
-    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported();
-    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported();
-    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported;
-    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported;
-    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+    EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
   };
 };
 
@@ -75,12 +65,10 @@ struct E {
     __declspec(dllimport) void fn_imported();
   };
 
-  struct __declspec(dllexport) nested_exported_1 {
-    // expected-warning@-1{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct __declspec(dllexport) nested_exported_1 { // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
     EXCLUDE_ATTR void fn_excluded();
   };
-  struct __declspec(dllimport) nested_imported_1 {
-    // expected-warning@-1{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct __declspec(dllimport) nested_imported_1 { // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
     EXCLUDE_ATTR void fn_excluded();
   };
 

>From e068cd10d928c8f1175f32b3c5549c7531d10779 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Fri, 27 Feb 2026 19:19:54 +0900
Subject: [PATCH 3/4] adjust the nested_exported case

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td     |  3 +++
 clang/lib/Sema/SemaDeclCXX.cpp                       | 12 +++++++++---
 ...de_from_explicit_instantiation.ignore-dllattr.cpp |  8 ++++----
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3bded7c6f78e7..072dff9b47074 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3787,6 +3787,9 @@ def warn_redeclaration_without_import_attribute : Warning<
 def warn_dllattr_ignored_exclusion_takes_precedence : Warning<
   "%0 attribute ignored; %1 takes precedence">,
   InGroup<IgnoredAttributes>;
+def warn_exclusion_takes_precedence_over_dllattr : Warning<
+  "%0 attribute takes precedence over %1 attribute on the enclosing class">,
+  InGroup<IgnoredAttributes>;
 def warn_dllimport_dropped_from_inline_function : Warning<
   "%q0 redeclared inline; %1 attribute ignored">,
   InGroup<IgnoredAttributes>;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ed6da8bd317f6..ae9ab109077cb 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7231,9 +7231,15 @@ void Sema::CheckCompletedCXXClass(Scope *S, 
CXXRecordDecl *Record) {
   for (auto *D : Record->decls()) {
     if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) {
       if (auto *DA = getDLLAttr(D)) {
-        Diag(DA->getRange().getBegin(),
-             diag::warn_dllattr_ignored_exclusion_takes_precedence)
-            << *DA << EA;
+        if (DA->isInherited()) {
+          Diag(EA->getLoc(), 
diag::warn_exclusion_takes_precedence_over_dllattr)
+              << EA << DA;
+          Diag(DA->getLoc(), diag::note_attribute);
+        } else {
+          Diag(DA->getLoc(),
+               diag::warn_dllattr_ignored_exclusion_takes_precedence)
+              << DA << EA;
+        }
         D->dropAttrs<DLLExportAttr, DLLImportAttr>();
       }
     }
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
index 1714d387d2bec..f2a53ab9cf302 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
@@ -65,11 +65,11 @@ struct E {
     __declspec(dllimport) void fn_imported();
   };
 
-  struct __declspec(dllexport) nested_exported_1 { // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR void fn_excluded();
+  struct __declspec(dllexport) nested_exported_1 { // expected-note{{attribute 
is here}}
+    EXCLUDE_ATTR void fn_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute takes 
precedence over 'dllexport' attribute on the enclosing class}}
   };
-  struct __declspec(dllimport) nested_imported_1 { // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR void fn_excluded();
+  struct __declspec(dllimport) nested_imported_1 { // expected-note{{attribute 
is here}}
+    EXCLUDE_ATTR void fn_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute takes 
precedence over 'dllimport' attribute on the enclosing class}}
   };
 
   // Make sure that any warning isn't emitted if the nested type has no 
excluded members.

>From 86d053cff76a3308117504df3be5b0b268b6eeb8 Mon Sep 17 00:00:00 2001
From: kikairoya <[email protected]>
Date: Sun, 1 Mar 2026 21:04:40 +0900
Subject: [PATCH 4/4] warn only if both of an exclude attribute and a dll
 attribute are specified directly

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  15 +-
 clang/lib/Sema/SemaDeclAttr.cpp               |  35 ++++
 clang/lib/Sema/SemaDeclCXX.cpp                |  15 --
 ..._explicit_instantiation.ignore-dllattr.cpp | 156 ++++++++++++++----
 4 files changed, 165 insertions(+), 56 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 072dff9b47074..1b18c020766da 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3784,18 +3784,21 @@ def 
warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
 def warn_redeclaration_without_import_attribute : Warning<
   "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">,
   InGroup<MicrosoftInconsistentDllImport>;
-def warn_dllattr_ignored_exclusion_takes_precedence : Warning<
-  "%0 attribute ignored; %1 takes precedence">,
-  InGroup<IgnoredAttributes>;
-def warn_exclusion_takes_precedence_over_dllattr : Warning<
-  "%0 attribute takes precedence over %1 attribute on the enclosing class">,
-  InGroup<IgnoredAttributes>;
 def warn_dllimport_dropped_from_inline_function : Warning<
   "%q0 redeclared inline; %1 attribute ignored">,
   InGroup<IgnoredAttributes>;
 def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts 
with"
   " exception specification; attribute ignored">,
   InGroup<IgnoredAttributes>;
+def warn_dllattr_ignored_exclusion_takes_precedence : Warning<
+  "%0 attribute ignored; %1 takes precedence">,
+  InGroup<IgnoredAttributes>;
+def warn_attribute_ignored_on_non_member :
+  Warning<"%0 attribute ignored on a non-member declaration">,
+  InGroup<IgnoredAttributes>;
+def warn_attribute_ignored_in_non_template :
+  Warning<"%0 attribute ignored in a non-template context">,
+  InGroup<IgnoredAttributes>;
 def warn_attribute_ignored_on_non_definition :
   Warning<"%0 attribute ignored on a non-definition declaration">,
   InGroup<IgnoredAttributes>;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 3abc69d0e4b96..1b7f41061061d 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -48,6 +48,7 @@
 #include "clang/Sema/SemaBPF.h"
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaM68k.h"
 #include "clang/Sema/SemaMIPS.h"
 #include "clang/Sema/SemaMSP430.h"
@@ -705,6 +706,24 @@ static void 
handleExcludeFromExplicitInstantiationAttr(Sema &S, Decl *D,
         << AL << /*IsMember=*/!isa<CXXRecordDecl>(D);
     return;
   }
+
+  if (auto *DA = getDLLAttr(D); DA && !DA->isInherited()) {
+    if (auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+      if (RD->isTemplated()) {
+        S.Diag(DA->getLoc(),
+               diag::warn_dllattr_ignored_exclusion_takes_precedence)
+            << DA << AL;
+        D->dropAttrs<DLLExportAttr, DLLImportAttr>();
+      } else {
+        S.Diag(AL.getLoc(), diag::warn_attribute_ignored_in_non_template) << 
AL;
+        return;
+      }
+    } else {
+      S.Diag(AL.getLoc(), diag::warn_attribute_ignored_on_non_member) << AL;
+      return;
+    }
+  }
+
   D->addAttr(::new (S.Context)
                  ExcludeFromExplicitInstantiationAttr(S.Context, AL));
 }
@@ -6469,6 +6488,22 @@ static void handleDLLAttr(Sema &S, Decl *D, const 
ParsedAttr &A) {
     }
   }
 
+  if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) {
+    if (auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+      if (RD->isTemplated()) {
+        S.Diag(A.getRange().getBegin(),
+               diag::warn_dllattr_ignored_exclusion_takes_precedence)
+            << A << EA;
+        return;
+      }
+      S.Diag(EA->getLoc(), diag::warn_attribute_ignored_in_non_template) << EA;
+      D->dropAttr<ExcludeFromExplicitInstantiationAttr>();
+    } else {
+      S.Diag(EA->getLoc(), diag::warn_attribute_ignored_on_non_member) << EA;
+      D->dropAttr<ExcludeFromExplicitInstantiationAttr>();
+    }
+  }
+
   Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport
                       ? (Attr *)S.mergeDLLExportAttr(D, A)
                       : (Attr *)S.mergeDLLImportAttr(D, A);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ae9ab109077cb..5837ecd6b9163 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7229,21 +7229,6 @@ void Sema::CheckCompletedCXXClass(Scope *S, 
CXXRecordDecl *Record) {
   bool HasMethodWithOverrideControl = false,
        HasOverridingMethodWithoutOverrideControl = false;
   for (auto *D : Record->decls()) {
-    if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) {
-      if (auto *DA = getDLLAttr(D)) {
-        if (DA->isInherited()) {
-          Diag(EA->getLoc(), 
diag::warn_exclusion_takes_precedence_over_dllattr)
-              << EA << DA;
-          Diag(DA->getLoc(), diag::note_attribute);
-        } else {
-          Diag(DA->getLoc(),
-               diag::warn_dllattr_ignored_exclusion_takes_precedence)
-              << DA << EA;
-        }
-        D->dropAttrs<DLLExportAttr, DLLImportAttr>();
-      }
-    }
-
     if (auto *M = dyn_cast<CXXMethodDecl>(D)) {
       // FIXME: We could do this check for dependent types with non-dependent
       // bases.
diff --git 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
index f2a53ab9cf302..5943f99e14cad 100644
--- 
a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
+++ 
b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp
@@ -2,85 +2,171 @@
 // RUN: %clang_cc1 -triple x86_64-mingw                 -fsyntax-only -verify 
%s
 // RUN: %clang_cc1 -triple x86_64-cygwin                -fsyntax-only -verify 
%s
 
-// Test that memberwise dllexport and dllimport are warned if the
-// exclude_from_explicit_instantiation attribute is attached.
+// Test that attaching the exclude_from_explicit_instantiation attribute and
+// either the dllexport or dllimport attribute together causes a warning.
+// One of them is ignored, depending on the context that is declared.
 
 #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation))
 
+// Test that exclude_from_explicit_instantiation takes precedence over
+// dllexport/dllimport in a template context.
 template <class T>
-struct C {
+struct class_tmpl_no_instantiated {
   EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
   EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  __declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  __declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+
   EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
   EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  __declspec(dllexport) EXCLUDE_ATTR static int var_exported_excluded; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  __declspec(dllimport) EXCLUDE_ATTR static int var_imported_excluded; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+
   struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
   struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct __declspec(dllexport) EXCLUDE_ATTR nested_exported_excluded {}; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  struct __declspec(dllimport) EXCLUDE_ATTR nested_imported_excluded {}; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+
+  template <class U>
+  struct EXCLUDE_ATTR __declspec(dllexport) nested_tmpl_excluded_exported {}; 
// expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  template <class U>
+  EXCLUDE_ATTR __declspec(dllexport) static T var_template_excluded; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  template <class U>
+  EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+
+  struct nested {
+    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  };
 
-  // No warnings here since nested_excluded is not instantiated.
   struct EXCLUDE_ATTR nested_excluded {
     __declspec(dllexport) void fn_exported();
-    __declspec(dllimport) void fn_imported();
   };
-  // This too. nested_exported is not instantiated.
   struct __declspec(dllexport) nested_exported {
     EXCLUDE_ATTR void fn_excluded();
-    EXCLUDE_ATTR static int var_excluded;
   };
-  // The same. nested_imported is not instantiated.
   struct __declspec(dllimport) nested_imported {
     EXCLUDE_ATTR void fn_excluded();
-    EXCLUDE_ATTR static int var_excluded;
   };
 
-  struct nested {
+  template <class U>
+  struct nested_tmpl {
     EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
-    EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // 
expected-warning{{'dllimport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
   };
 };
 
-// Test that class-level dll attributes doesn't cause a warning on an excluded 
member.
+// Test that a class-level dll attribute doesn't cause a warning on an 
excluded member.
 template <class T>
-struct __declspec(dllexport) DE {
+struct __declspec(dllexport) class_tmpl_exported {
   EXCLUDE_ATTR void fn_excluded();
 };
-template struct DE<int>;
+template struct class_tmpl_exported<int>;
+void use_class_tmpl_exported() { class_tmpl_exported<long>().fn_excluded(); }
 
 template <class T>
-struct __declspec(dllimport) DI {
+struct __declspec(dllimport) class_tmpl_imported {
   EXCLUDE_ATTR void fn_excluded();
 };
-template struct DI<int>;
+template struct class_tmpl_imported<int>;
+void use_class_tmpl_imported() { class_tmpl_imported<long>().fn_excluded(); }
 
-// Test that dll attributes on explicit instantiation doesn't cause a warning 
on
+// Test that a dll attribute on an explicit instantiation doesn't cause a 
warning on
 // an excluded member.
-// However, a non-template nested type may be warned on an excluded member by
-// its dll attribute.
 template <class T>
-struct E {
+struct class_tmpl_explicit_inst {
   EXCLUDE_ATTR void fn_excluded();
+  EXCLUDE_ATTR static T var_excluded;
   struct EXCLUDE_ATTR nested_excluded {
     __declspec(dllexport) void fn_exported();
     __declspec(dllimport) void fn_imported();
   };
 
-  struct __declspec(dllexport) nested_exported_1 { // expected-note{{attribute 
is here}}
-    EXCLUDE_ATTR void fn_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute takes 
precedence over 'dllexport' attribute on the enclosing class}}
+  struct __declspec(dllexport) nested_exported {
+    EXCLUDE_ATTR void fn_excluded();
   };
-  struct __declspec(dllimport) nested_imported_1 { // expected-note{{attribute 
is here}}
-    EXCLUDE_ATTR void fn_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute takes 
precedence over 'dllimport' attribute on the enclosing class}}
+  struct __declspec(dllimport) nested_imported {
+    EXCLUDE_ATTR void fn_excluded();
   };
+};
+extern template struct __declspec(dllimport) class_tmpl_explicit_inst<long>;
+template struct __declspec(dllexport) class_tmpl_explicit_inst<int>;
+
+// Test that exclude_from_explicit_instantiation is ignored in a non-template 
context.
+struct class_nontmpl {
+  EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  __declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  __declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+
+  EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  __declspec(dllexport) EXCLUDE_ATTR static int var_exported_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  __declspec(dllimport) EXCLUDE_ATTR static int var_imported_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+
+  struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  struct __declspec(dllexport) EXCLUDE_ATTR nested_exported_excluded {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  struct __declspec(dllimport) EXCLUDE_ATTR nested_imported_excluded {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+
+  template <class T>
+  struct EXCLUDE_ATTR __declspec(dllexport) class_template_excluded {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  template <class T>
+  EXCLUDE_ATTR __declspec(dllexport) static T var_template_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
+  template <class T>
+  EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
 
-  // Make sure that any warning isn't emitted if the nested type has no 
excluded members.
-  struct __declspec(dllexport) nested_exported_2 {
-    void fn();
+  struct nested {
+    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a 
non-template context}}
   };
-  struct __declspec(dllimport) nested_imported_2 {
-    void fn();
+
+  struct EXCLUDE_ATTR nested_excluded {
+    __declspec(dllexport) void fn_excluded_exported();
   };
+  struct __declspec(dllexport) nested_exported {
+    EXCLUDE_ATTR void fn_excluded();
+  };
+  struct __declspec(dllimport) nested_imported {
+    EXCLUDE_ATTR void fn_excluded();
+  };
+
+  template <class T>
+  struct nested_tmpl {
+    EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'dllexport' attribute ignored; 
'exclude_from_explicit_instantiation' takes precedence}}
+  };
+};
+
+// Test that exclude_from_explicit_instantiation is ignored on a non-member 
entity.
+EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+__declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+__declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+
+EXCLUDE_ATTR __declspec(dllexport) int var_excluded_exported; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+EXCLUDE_ATTR __declspec(dllimport) int var_excluded_imported; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+__declspec(dllexport) EXCLUDE_ATTR int var_exported_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+__declspec(dllimport) EXCLUDE_ATTR int var_imported_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+
+struct EXCLUDE_ATTR __declspec(dllexport) class_excluded_exported {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+struct EXCLUDE_ATTR __declspec(dllimport) class_excluded_imported {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+struct __declspec(dllexport) EXCLUDE_ATTR class_exported_excluded {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+struct __declspec(dllimport) EXCLUDE_ATTR class_imported_excluded {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+
+template <class T>
+struct EXCLUDE_ATTR __declspec(dllexport) class_tmpl_excluded_exported {}; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+template <class T>
+EXCLUDE_ATTR __declspec(dllexport) T var_template_excluded; // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+template <class T>
+EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // 
expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a 
non-member declaration}}
+
+EXCLUDE_ATTR void fn_excluded();
+
+EXCLUDE_ATTR int var_excluded;
+
+struct EXCLUDE_ATTR class_excluded {
+  __declspec(dllexport) void fn_excluded_exported();
+};
+struct __declspec(dllexport) class_exported {
+  EXCLUDE_ATTR void fn_excluded();
+};
+struct __declspec(dllimport) class_imported {
+  EXCLUDE_ATTR void fn_excluded();
 };
-extern template struct __declspec(dllimport) E<long>;
-template struct __declspec(dllexport) E<int>;
-// expected-note@-1{{in instantiation of member class 
'E<int>::nested_exported_1' requested here}}
-// expected-note@-2{{in instantiation of member class 
'E<int>::nested_imported_1' requested here}}

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

Reply via email to