Author: mstorsjo
Date: Fri Apr 26 01:09:51 2019
New Revision: 359285

URL: http://llvm.org/viewvc/llvm-project?rev=359285&view=rev
Log:
[MinGW] Fix dllexport of explicit template instantiation

Contrary to MSVC, GCC/MinGW needs to have the dllexport attribute
on the template instantiation declaration, not on the definition.

Previously clang never marked explicit template instantiations as
dllexport in MinGW mode, if the instantiation had a previous
declaration, regardless of where the attribute was placed. This
makes Clang behave like GCC in this regard, and allows using the
same attribute form for both MinGW compilers.

This fixes PR40256.

Differential Revision: https://reviews.llvm.org/D61118

Added:
    cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaCXX/dllexport.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=359285&r1=359284&r2=359285&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Apr 26 01:09:51 
2019
@@ -2863,6 +2863,9 @@ def warn_attribute_dllimport_static_fiel
 def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
   "explicit instantiation declaration should not be 'dllexport'">,
   InGroup<DiagGroup<"dllexport-explicit-instantiation-decl">>;
+def warn_attribute_dllexport_explicit_instantiation_def : Warning<
+  "'dllexport' attribute ignored on explicit instantiation definition">,
+  InGroup<IgnoredAttributes>;
 def warn_invalid_initializer_from_system_header : Warning<
   "invalid constructor form class in system header, should not be explicit">,
   InGroup<DiagGroup<"invalid-initializer-from-system-header">>;

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=359285&r1=359284&r2=359285&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Apr 26 01:09:51 2019
@@ -5697,9 +5697,11 @@ void Sema::checkClassLevelDLLAttribute(C
 
   TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
 
-  // Ignore explicit dllexport on explicit class template instantiation 
declarations.
+  // Ignore explicit dllexport on explicit class template instantiation
+  // declarations, except in MinGW mode.
   if (ClassExported && !ClassAttr->isInherited() &&
-      TSK == TSK_ExplicitInstantiationDeclaration) {
+      TSK == TSK_ExplicitInstantiationDeclaration &&
+      !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
     Class->dropAttr<DLLExportAttr>();
     return;
   }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=359285&r1=359284&r2=359285&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Apr 26 01:09:51 2019
@@ -8732,8 +8732,10 @@ DeclResult Sema::ActOnExplicitInstantiat
                                        ? TSK_ExplicitInstantiationDefinition
                                        : TSK_ExplicitInstantiationDeclaration;
 
-  if (TSK == TSK_ExplicitInstantiationDeclaration) {
-    // Check for dllexport class template instantiation declarations.
+  if (TSK == TSK_ExplicitInstantiationDeclaration &&
+      !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
+    // Check for dllexport class template instantiation declarations,
+    // except for MinGW mode.
     for (const ParsedAttr &AL : Attr) {
       if (AL.getKind() == ParsedAttr::AT_DLLExport) {
         Diag(ExternLoc,
@@ -8793,6 +8795,19 @@ DeclResult Sema::ActOnExplicitInstantiat
   TemplateSpecializationKind PrevDecl_TSK
     = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
 
+  if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr &&
+      Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
+    // 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) {
+        Diag(AL.getLoc(),
+             diag::warn_attribute_dllexport_explicit_instantiation_def);
+        break;
+      }
+    }
+  }
+
   if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
                                  SS.isSet(), TSK))
     return true;
@@ -8949,6 +8964,14 @@ DeclResult Sema::ActOnExplicitInstantiat
       dllExportImportClassTemplateSpecialization(*this, Def);
     }
 
+    // In MinGW mode, export the template instantiation if the declaration
+    // was marked dllexport.
+    if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
+        Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() &&
+        PrevDecl->hasAttr<DLLExportAttr>()) {
+      dllExportImportClassTemplateSpecialization(*this, Def);
+    }
+
     // Set the template specialization kind. Make sure it is set before
     // instantiating the members which will trigger ASTConsumer callbacks.
     Specialization->setTemplateSpecializationKind(TSK);

Added: cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp?rev=359285&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp Fri Apr 26 01:09:51 
2019
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -emit-llvm -triple i686-mingw32 %s -o - | FileCheck %s
+
+template <class T>
+class c {
+  void f();
+};
+
+template <class T> void c<T>::f() {}
+
+template class __declspec(dllexport) c<int>;
+
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
+
+extern template class __declspec(dllexport) c<char>;
+template class c<char>;
+
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
+
+extern template class c<double>;
+template class __declspec(dllexport) c<double>;
+
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
+
+template <class T>
+struct outer {
+  void f();
+  struct inner {
+    void f();
+  };
+};
+
+template <class T> void outer<T>::f() {}
+template <class T> void outer<T>::inner::f() {}
+
+template class __declspec(dllexport) outer<int>;
+
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv

Modified: cfe/trunk/test/SemaCXX/dllexport.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllexport.cpp?rev=359285&r1=359284&r2=359285&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllexport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllexport.cpp Fri Apr 26 01:09:51 2019
@@ -367,10 +367,16 @@ ImplicitlyInstantiatedExportedTemplate<I
 
 // Don't instantiate class members of templates with explicit instantiation 
declarations, even if they are exported.
 struct IncompleteType2;
-template <typename T> struct __declspec(dllexport) 
ExportedTemplateWithExplicitInstantiationDecl { // expected-note{{attribute is 
here}}
+#ifdef MS
+// expected-note@+2{{attribute is here}}
+#endif
+template <typename T> struct __declspec(dllexport) 
ExportedTemplateWithExplicitInstantiationDecl {
   int f() { return sizeof(T); } // no-error
 };
-extern template struct 
ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>; // 
expected-warning{{explicit instantiation declaration should not be 'dllexport'}}
+#ifdef MS
+// expected-warning@+2{{explicit instantiation declaration should not be 
'dllexport'}}
+#endif
+extern template struct 
ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
 
 // Instantiate class members for explicitly instantiated exported templates.
 struct IncompleteType3; // expected-note{{forward declaration of 
'IncompleteType3'}}
@@ -402,10 +408,17 @@ struct __declspec(dllexport) ExportedBas
 
 // Warn about explicit instantiation declarations of dllexport classes.
 template <typename T> struct ExplicitInstantiationDeclTemplate {};
-extern template struct __declspec(dllexport) 
ExplicitInstantiationDeclTemplate<int>; // expected-warning{{explicit 
instantiation declaration should not be 'dllexport'}} expected-note{{attribute 
is here}}
+#ifdef MS
+// expected-warning@+2{{explicit instantiation declaration should not be 
'dllexport'}} expected-note@+2{{attribute is here}}
+#endif
+extern template struct __declspec(dllexport) 
ExplicitInstantiationDeclTemplate<int>;
 
-template <typename T> struct __declspec(dllexport) 
ExplicitInstantiationDeclExportedTemplate {}; // expected-note{{attribute is 
here}}
-extern template struct ExplicitInstantiationDeclExportedTemplate<int>; // 
expected-warning{{explicit instantiation declaration should not be 'dllexport'}}
+template <typename T> struct __declspec(dllexport) 
ExplicitInstantiationDeclExportedTemplate {};
+#ifdef MS
+// expected-note@-2{{attribute is here}}
+// expected-warning@+2{{explicit instantiation declaration should not be 
'dllexport'}}
+#endif
+extern template struct ExplicitInstantiationDeclExportedTemplate<int>;
 
 namespace { struct InternalLinkageType {}; }
 struct __declspec(dllexport) PR23308 {
@@ -438,6 +451,12 @@ template <typename T> struct ExplicitlyI
 template struct ExplicitlyInstantiatedTemplate<int>;
 template <typename T> struct ExplicitlyExportInstantiatedTemplate { void 
func() {} };
 template struct __declspec(dllexport) 
ExplicitlyExportInstantiatedTemplate<int>;
+template <typename T> struct ExplicitlyExportDeclaredInstantiatedTemplate { 
void func() {} };
+extern template struct ExplicitlyExportDeclaredInstantiatedTemplate<int>;
+#ifndef MS
+// expected-warning@+2{{'dllexport' attribute ignored on explicit 
instantiation definition}}
+#endif
+template struct __declspec(dllexport) 
ExplicitlyExportDeclaredInstantiatedTemplate<int>;
 template <typename T> struct ExplicitlyImportInstantiatedTemplate { void 
func() {} };
 template struct __declspec(dllimport) 
ExplicitlyImportInstantiatedTemplate<int>;
 


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

Reply via email to