]> granicus.if.org Git - clang/commitdiff
[MinGW] Don't let template instantiation declarations cover nested classes
authorMartin Storsjo <martin@martin.st>
Fri, 26 Apr 2019 19:31:39 +0000 (19:31 +0000)
committerMartin Storsjo <martin@martin.st>
Fri, 26 Apr 2019 19:31:39 +0000 (19:31 +0000)
An explicit template instantiation declaration used to let
callers assume both outer and nested classes instantiations were
defined in a different translation unit.

If the instantiation is marked dllexport, only the outer class
is exported, but the caller will try to reference the instantiation
of both outer and inner classes.

This makes MinGW mode match both MSVC and Windows Itanium, by
having instantations only cover the outer class, and locally emitting
definitions of the nested classes. Windows Itanium was changed to
use this behavious in SVN r300804.

This deviates from what GCC does, but should be safe (and only
inflate the object file size a bit, but MSVC and Windows Itanium
modes do the same), and fixes cases where inner classes aren't
dllexported.

This fixes missing references in combination with dllexported/imported
template intantiations.

GCC suffers from the same issue, reported at [1], but the issue
is still unresolved there. The issue can probably be solved either
by making dllexport cover all nested classes as well, or this
way (matching MSVC).

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89087

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359342 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateInstantiate.cpp
test/CodeGenCXX/mingw-template-dllexport.cpp

index c7457354b3323d15a62e796478e6eb45464f5b2d..a7be1ea7c89ee89cd005b1aca99574b7b45b57a0 100644 (file)
@@ -2685,10 +2685,14 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
         continue;
 
       if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
-           Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
+           Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() ||
+           Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) &&
           TSK == TSK_ExplicitInstantiationDeclaration) {
         // In MSVC and Windows Itanium mode, explicit instantiation decl of the
         // outer class doesn't affect the inner class.
+        // In GNU mode, inner classes aren't dllexported. Don't let the
+        // instantiation cover the inner class, to avoid undefined references
+        // to inner classes that weren't exported.
         continue;
       }
 
index 478c4dfb2881d2a2e3fbeaac3f47a78504523cc6..9e8f9b1bccff9c85144e4506f67c7878da245016 100644 (file)
@@ -1,5 +1,10 @@
 // RUN: %clang_cc1 -emit-llvm -triple i686-mingw32 %s -o - | FileCheck %s
 
+#define JOIN2(x, y) x##y
+#define JOIN(x, y) JOIN2(x, y)
+#define UNIQ(name) JOIN(name, __LINE__)
+#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
+
 template <class T>
 class c {
   void f();
@@ -36,3 +41,10 @@ template class __declspec(dllexport) outer<int>;
 
 // CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
 // CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
+
+extern template class __declspec(dllimport) outer<char>;
+USEMEMFUNC(outer<char>, f)
+USEMEMFUNC(outer<char>::inner, f)
+
+// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
+// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv