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

>From 4f0eab77111d15515082c82d288f25ca88424a9e Mon Sep 17 00:00:00 2001
From: kikairoya <kikair...@gmail.com>
Date: Mon, 21 Apr 2025 23:30:13 +0900
Subject: [PATCH 1/2] [Cygwin][MinGW] Internal class in
 explicitly-instantiation-declarated template should be instantiated

In-code comment says "explicit instantiation decl of the outer class
doesn't affect the inner class" but this behavior seems MSVC
specific, MinGW-GCC and Cygwin-GCC does not.
Clang should honor gcc's behavior.

This change fixes std::string compatibilty and resolves strange link
error (statically linked), strange crash (dynamically linked) using
libstdc++ on Cygwin.
---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |   1 +
 .../CodeGenCXX/mingw-template-dllexport.cpp   | 109 +++++++++++++++---
 2 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index d028eea4f8f3e..b7c27b3795f5d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -4247,6 +4247,7 @@ Sema::InstantiateClassMembers(SourceLocation 
PointOfInstantiation,
         continue;
 
       if (Context.getTargetInfo().getTriple().isOSWindows() &&
+          !Context.getTargetInfo().getTriple().isOSCygMing() &&
           TSK == TSK_ExplicitInstantiationDeclaration) {
         // On Windows, explicit instantiation decl of the outer class doesn't
         // affect the inner class. Typically extern template declarations are
diff --git a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp 
b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
index de112d6da53db..a6047b5955e96 100644
--- a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
+++ b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
@@ -6,46 +6,121 @@
 #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; }
+#define USEMEMFUNC(class, func) auto UNIQ(use) = &class::func;
 
 template <class T>
 class c {
+  // MinGW-GCC does not apply 'dllexport' to inline member function in 
dll-exported template but clang does from long ago.
   void f() {}
+  void g();
+  inline static int u = 0;
+  static int v;
 };
+template <class T> void c<T>::g() {}
+template <class T> int c<T>::v = 0;
 
+// #1
 template class __declspec(dllexport) c<int>;
 
-// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
-
+// #2
 extern template class __declspec(dllexport) c<char>;
 template class c<char>;
 
-// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
-
+// #3
 extern template class c<double>;
-template class __declspec(dllexport) c<double>;
+template class __declspec(dllexport) c<double>; // expected-warning {{ 
'dllexport' attribute ignored on explicit instantiation definition }}
 
-// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
 
 template <class T>
 struct outer {
-  void f();
+  void f() {}
+  void g();
+  inline static int u = 0;
+  static int v;
+  // MinGW-GCC and Clang does not apply 'dllexport' to inner type and its 
sub-elements in template class.
   struct inner {
-    void f();
+    void f() {}
+    void g();
+    inline static int u = 0;
+    static int v;
   };
 };
 
-template <class T> void outer<T>::f() {}
-template <class T> void outer<T>::inner::f() {}
+template <class T> void outer<T>::g() {}
+template <class T> void outer<T>::inner::g() {}
+template <class T> int outer<T>::v = 0;
+template <class T> int outer<T>::inner::v = 0;
 
-template class __declspec(dllexport) outer<int>;
+// #4
+template struct __declspec(dllexport) outer<int>;
 
-// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
-// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
-
-extern template class __declspec(dllimport) outer<char>;
+// #5
+extern template struct __declspec(dllimport) outer<char>;
 USEMEMFUNC(outer<char>, f)
+USEMEMFUNC(outer<char>, g)
+USEMEMFUNC(outer<char>, u)
+USEMEMFUNC(outer<char>, v)
 USEMEMFUNC(outer<char>::inner, f)
+USEMEMFUNC(outer<char>::inner, g)
+USEMEMFUNC(outer<char>::inner, u)
+USEMEMFUNC(outer<char>::inner, v)
+
+
+// #1 variables
+// CHECK: @_ZN1cIiE1uE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN1cIiE1vE = {{.*}} dllexport {{.*}}
+
+// #2 variables
+// CHECK: @_ZN1cIcE1uE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN1cIcE1vE = {{.*}} dllexport {{.*}}
+
+// #3 variables
+// CHECK: @_ZN1cIdE1uE = {{.*}}
+// CHECK-NOT: @_ZN1cIcE1uE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN1cIdE1vE = {{.*}}
+// CHECK-NOT: @_ZN1cIcE1vE = {{.*}} dllexport {{.*}}
+
+// #4 variables
+// CHECK: @_ZN5outerIiE1uE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN5outerIiE1vE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN5outerIiE5inner1uE = {{.*}}
+// CHECK-NOT: @_ZN5outerIiE5inner1uE = {{.*}} dllexport {{.*}}
+// CHECK: @_ZN5outerIiE5inner1vE = {{.*}}
+// CHECK-NOT: @_ZN5outerIiE5inner1vE = {{.*}} dllexport {{.*}}
+
+// #5 variables
+// CHECK: @_ZN5outerIcE1uE = external dllimport {{.*}}
+// CHECK: @_ZN5outerIcE1vE = external dllimport {{.*}}
+// CHECK-NOT: @_ZN5outerIcE5inner1uE = dllimport {{.*}}
+// CHECK-NOT: @_ZN5outerIcE5inner1vE = dllimport {{.*}}
+// CHECK: @_ZN5outerIcE5inner1uE = external {{.*}}
+// CHECK: @_ZN5outerIcE5inner1vE = external {{.*}}
+
+
+// #1 functions
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1gEv
+
+// #2 functions
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1gEv
+
+// #3 functions
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1gEv
+
+// #4 functions
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1gEv
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1gEv
 
+// #5 functions
 // CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
-// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv
+// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1gEv
+// CHECK-NOT: declare dllimport {{.*}} @_ZN5outerIcE5inner1fEv
+// CHECK-NOT: declare dllimport {{.*}} @_ZN5outerIcE5inner1gEv
+// CHECK-NOT: define {{.*}} @_ZN5outerIcE1fEv
+// CHECK-NOT: define {{.*}} @_ZN5outerIcE5inner1fEv
+// CHECK-NOT: define {{.*}} @_ZN5outerIcE1gEv
+// CHECK-NOT: define {{.*}} @_ZN5outerIcE5inner1gEv

>From 92a3b90dbc4affe081eb5f6ebb8413d415ecc079 Mon Sep 17 00:00:00 2001
From: kikairoya <kikair...@gmail.com>
Date: Sat, 17 May 2025 16:22:42 +0900
Subject: [PATCH 2/2] [libc++] std::ostream::sentry should excluded from
 explicit instantiation on client-side

---
 libcxx/docs/DesignDocs/VisibilityMacros.rst | 5 +++++
 libcxx/include/__config                     | 8 ++++++++
 libcxx/include/__ostream/basic_ostream.h    | 2 +-
 libcxx/include/istream                      | 2 +-
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/libcxx/docs/DesignDocs/VisibilityMacros.rst 
b/libcxx/docs/DesignDocs/VisibilityMacros.rst
index e9f88118b7ef3..b56ddf53dbfdc 100644
--- a/libcxx/docs/DesignDocs/VisibilityMacros.rst
+++ b/libcxx/docs/DesignDocs/VisibilityMacros.rst
@@ -93,6 +93,11 @@ Visibility Macros
   the extern template declaration) as exported on Windows, as discussed above.
   On all other platforms, this macro has an empty definition.
 
+**_LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS**
+  To keep binary compatibility purpose only of a class not marked as 
`dllexport`
+  that is defined in a class template. Not to add this for new class, and this
+  can be replaced to `_LIBCPP_EXPORTED_FROM_ABI` at a timing of ABI change 
occurs.
+
 Links
 =====
 
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 110450f6e9c51..91b75860c84ef 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -365,6 +365,11 @@ typedef __char32_t char32_t;
 #      define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
 #      define _LIBCPP_OVERRIDABLE_FUNC_VIS
 #      define _LIBCPP_EXPORTED_FROM_ABI
+#      if defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) || 
!__has_attribute(exclude_from_explicit_instantiation)
+#        define _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS
+#      else
+#        define _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS 
__attribute__((__exclude_from_explicit_instantiation__))
+#      endif
 #    elif defined(_LIBCPP_BUILDING_LIBRARY)
 #      if defined(__MINGW32__)
 #        define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __declspec(dllexport)
@@ -375,11 +380,13 @@ typedef __char32_t char32_t;
 #      endif
 #      define _LIBCPP_OVERRIDABLE_FUNC_VIS __declspec(dllexport)
 #      define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllexport)
+#      define _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS
 #    else
 #      define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __declspec(dllimport)
 #      define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
 #      define _LIBCPP_OVERRIDABLE_FUNC_VIS
 #      define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllimport)
+#      define _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS
 #    endif
 
 #    define _LIBCPP_HIDDEN
@@ -399,6 +406,7 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_VISIBILITY("default")
 #    define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_VISIBILITY("default")
 #    define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
+#    define _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS
 
 // TODO: Make this a proper customization point or remove the option to 
override it.
 #    ifndef _LIBCPP_OVERRIDABLE_FUNC_VIS
diff --git a/libcxx/include/__ostream/basic_ostream.h 
b/libcxx/include/__ostream/basic_ostream.h
index f7473a36d8ccc..a72350501ccda 100644
--- a/libcxx/include/__ostream/basic_ostream.h
+++ b/libcxx/include/__ostream/basic_ostream.h
@@ -71,7 +71,7 @@ class basic_ostream : virtual public basic_ios<_CharT, 
_Traits> {
 
 public:
   // 27.7.2.4 Prefix/suffix:
-  class sentry;
+  class _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS sentry;
 
   // 27.7.2.6 Formatted output:
   inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& 
operator<<(basic_ostream& (*__pf)(basic_ostream&)) {
diff --git a/libcxx/include/istream b/libcxx/include/istream
index 95340c739c118..b41dd59060f78 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -228,7 +228,7 @@ public:
   basic_istream& operator=(const basic_istream& __rhs) = delete;
 
   // 27.7.1.1.3 Prefix/suffix:
-  class sentry;
+  class _LIBCPP_INNER_CLASS_IN_TEMPLATE_VIS sentry;
 
   // 27.7.1.2 Formatted input:
   inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& 
operator>>(basic_istream& (*__pf)(basic_istream&)) {

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

Reply via email to