https://github.com/philnik777 created 
https://github.com/llvm/llvm-project/pull/133699

MinGW and Win32 disagree on where the `__declspec(dllexport)` should be placed. 
However, there doesn't
fundamentally seem to be a problem with putting the annotation in both places. 
This patch adds a new
diagnostic group and `-Wattribute-ignored` warnings about where the attribute 
is placed if the attribute
is different on the declaration and definition. There is another new warning 
group
`-Wdllexport-explicit-instantiation` that also diagnoses places where the 
attribue is technically ignored,
even though the correct place is also annotated. This makes it possible to 
significantly simplify libc++'s
visibility annotations.


>From e4178604a738d91e1880df968efed63b248520ac Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklau...@berlin.de>
Date: Sun, 30 Mar 2025 14:10:26 +0200
Subject: [PATCH] [Clang] Allow simpler visibility annotations when targeting
 win32 and mingw

---
 clang/include/clang/Basic/Attr.td             |  8 ++++++++
 clang/include/clang/Basic/DiagnosticGroups.td |  6 +++++-
 .../clang/Basic/DiagnosticSemaKinds.td        | 12 ++++++++++-
 clang/lib/Sema/SemaDeclCXX.cpp                |  5 ++++-
 clang/lib/Sema/SemaTemplate.cpp               | 20 +++++++++++++++++--
 .../dllexport-explicit-instantiation.cpp      | 19 ++++++++++++++++++
 6 files changed, 65 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/SemaCXX/dllexport-explicit-instantiation.cpp

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 0999d8065e9f5..6bb8fc05b119a 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4185,6 +4185,14 @@ def DLLExport : InheritableAttr, 
TargetSpecificAttr<TargetHasDLLImportExport> {
   let Documentation = [DLLExportDocs];
 }
 
+def DLLExportOnDecl : InheritableAttr, 
TargetSpecificAttr<TargetHasDLLImportExport> {
+  // This attribute is only used to warn if there was a `__declspec(dllexport)`
+  // on a declaration, but not on the defintion of an explciit instantiation
+  let Spellings = [];
+  let Subjects = SubjectList<[CXXRecord]>;
+  let Documentation = [InternalOnly];
+}
+
 def DLLExportStaticLocal : InheritableAttr, 
TargetSpecificAttr<TargetHasDLLImportExport> {
   // This attribute is used internally only when -fno-dllexport-inlines is
   // passed. This attribute is added to inline functions of a class having the
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index b9f08d96151c9..80f27771248bb 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -487,6 +487,9 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment,
                                       ReturnStackAddress]>;
 def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
 def DllexportExplicitInstantiationDecl : 
DiagGroup<"dllexport-explicit-instantiation-decl">;
+def DllexportExplicitInstantiation :
+  DiagGroup<"dllexport-explicit-instantiation",
+            [DllexportExplicitInstantiationDecl]>;
 def ExcessInitializers : DiagGroup<"excess-initializers">;
 def ExpansionToDefined : DiagGroup<"expansion-to-defined">;
 def FlagEnum : DiagGroup<"flag-enum">;
@@ -870,7 +873,8 @@ def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">;
 
 def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
 def UnknownAttributes : DiagGroup<"unknown-attributes">;
-def IgnoredAttributes : DiagGroup<"ignored-attributes">;
+def IgnoredAttributes : DiagGroup<"ignored-attributes",
+                                  [DllexportExplicitInstantiation]>;
 def Attributes : DiagGroup<"attributes", [UnknownAttributes,
                                           IgnoredAttributes]>;
 def UnknownSanitizers : DiagGroup<"unknown-sanitizers">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1e900437d41ce..31324b6b1262f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3736,9 +3736,19 @@ def warn_attribute_dllimport_static_field_definition : 
Warning<
 def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
   "explicit instantiation declaration should not be 'dllexport'">,
   InGroup<DllexportExplicitInstantiationDecl>;
-def warn_attribute_dllexport_explicit_instantiation_def : Warning<
+def warn_attr_dllexport_explicit_inst_def : Warning<
   "'dllexport' attribute ignored on explicit instantiation definition">,
+  InGroup<DllexportExplicitInstantiation>;
+def warn_attr_dllexport_explicit_inst_def_mismatch : Warning<
+  "'dllexport' attribute ignored on explicit instantiation definition">,
+  InGroup<IgnoredAttributes>;
+def note_prev_decl_missing_dllexport : Note<
+  "'dllexport' attribute is missing on previous declaration">;
+def warn_dllexport_on_decl_ignored : Warning<
+  "explicit instantiation definition is not exported without 'dllexport'">,
   InGroup<IgnoredAttributes>;
+def note_dllexport_on_decl : Note<
+  "'dllexport' attribute on the declaration is ignored">;
 def warn_attribute_exclude_from_explicit_instantiation_local_class : Warning<
   "%0 attribute ignored on local class%select{| member}1">,
   InGroup<IgnoredAttributes>;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 676d53a1f4b45..4d69c11678620 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6606,7 +6606,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl 
*Class) {
   if (ClassExported && !ClassAttr->isInherited() &&
       TSK == TSK_ExplicitInstantiationDeclaration &&
       !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
-    Class->dropAttr<DLLExportAttr>();
+    if (auto *DEA = Class->getAttr<DLLExportAttr>()) {
+      Class->addAttr(DLLExportOnDeclAttr::Create(Context, DEA->getLoc()));
+      Class->dropAttr<DLLExportAttr>();
+    }
     return;
   }
 
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index be81b6a46b2c0..25d84fde65970 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -9845,13 +9845,29 @@ DeclResult Sema::ActOnExplicitInstantiation(
     // mode, if a previous declaration of the instantiation was seen.
     for (const ParsedAttr &AL : Attr) {
       if (AL.getKind() == ParsedAttr::AT_DLLExport) {
-        Diag(AL.getLoc(),
-             diag::warn_attribute_dllexport_explicit_instantiation_def);
+        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 (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl &&
+      !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() &&
+      llvm::none_of(Attr, [](const ParsedAttr &AL) {
+        return AL.getKind() == ParsedAttr::AT_DLLExport;
+      })) {
+    if (const auto *DEA = PrevDecl->getAttr<DLLExportOnDeclAttr>()) {
+      Diag(TemplateLoc, diag::warn_dllexport_on_decl_ignored);
+      Diag(DEA->getLoc(), diag::note_dllexport_on_decl);
+    }
+  }
+
   if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
                                  SS.isSet(), TSK))
     return true;
diff --git a/clang/test/SemaCXX/dllexport-explicit-instantiation.cpp 
b/clang/test/SemaCXX/dllexport-explicit-instantiation.cpp
new file mode 100644
index 0000000000000..522e81d37976d
--- /dev/null
+++ b/clang/test/SemaCXX/dllexport-explicit-instantiation.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-win32   -fsyntax-only -fms-extensions 
-verify=win32,win32-pedantic -DMS %s -Wdllexport-explicit-instantiation
+// RUN: %clang_cc1 -triple x86_64-win32   -fsyntax-only -fms-extensions 
-verify=win32                -DMS %s -Wno-dllexport-explicit-instantiation
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions 
-verify=mingw,mingw-pedantic -DMS %s -Wdllexport-explicit-instantiation
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions 
-verify=mingw                -DMS %s -Wno-dllexport-explicit-instantiation
+
+template <class>
+class S {};
+
+extern template class __declspec(dllexport) S<short>; // 
win32-pedantic-warning {{explicit instantiation declaration should not be 
'dllexport'}} \
+                                                         win32-pedantic-note 
{{attribute is here}}
+template class __declspec(dllexport) S<short>;        // 
mingw-pedantic-warning {{'dllexport' attribute ignored on explicit 
instantiation definition}}
+
+extern template class __declspec(dllexport) S<int>;  // win32-pedantic-warning 
{{explicit instantiation declaration should not be 'dllexport'}} \
+                                                        win32-pedantic-note 
{{attribute is here}} \
+                                                        win32-note 
{{'dllexport' attribute on the declaration is ignored}}
+template class S<int>;                               // win32-warning 
{{explicit instantiation definition is not exported without 'dllexport'}}
+
+extern template class S<long>;                       // mingw-note 
{{'dllexport' attribute is missing on previous declaration}}
+template class __declspec(dllexport) S<long>;        // mingw-warning 
{{'dllexport' attribute ignored on explicit instantiation definition}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to