Skip to content

Commit 698c6a0

Browse files
committed
[libc++] Introduce a new attribute keyword for Clang improves compatibility with Mingw-GCC
The new ABI annotation keyword _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 is introduced. In MinGW environment, Clang handles dllexport attribute of internal class that defined in class template in different way from GCC. This incompatibility should be fixed but breaks ABI of libc++, so introduce a new keyword to keep ABI in MinGW environment with old and patched Clang and to stay ABI compatible on other platforms. This attribute is attached only for basic_ostream::sentry::sentry, basic_ostream::sentry::~sentry and basic_istream::sentry::sentry. Other entities won't be affected by patching Clang so doesn't need to be annotate. At a time to introduce a new (static or non-static) member function or a new static data member is added to an non-template inner class within a class template that has explicit instantiation declaration, all of such members need to be attached _LIBCPP_HIDE_FROM_ABI. Otherwise, that members contained in DLL will be inaccessible on MinGW environment.
1 parent ac4893d commit 698c6a0

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

libcxx/include/__config

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,50 @@ typedef __char32_t char32_t;
530530
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
531531
# endif
532532

533+
// _LIBCPP_HIDE_FROM_ABI is required for member functions defined within an inner class of a class template
534+
// (e.g., std::basic_ostream<...>::sentry::sentry(...)), due to inconsistent behavior in MinGW-GCC (and
535+
// Cygwin as well, in all relevant cases) regarding explicit instantiation declaration and symbol visibility
536+
// when combined with __declspec(dllexport).
537+
//
538+
// Previous versions of Clang did not exhibit this issue, but upcoming versions are expected to align with
539+
// GCC's behavior for compatibility. This is particularly important because some of libstdc++ packages
540+
// compiled with --with-default-libstdcxx-abi=gcc4-compatible are incompatible with Clang, resulting in linking
541+
// errors or runtime crushes.
542+
//
543+
// A few such member functions already exist (here are ostream::sentry::sentry, ostream::~sentry and
544+
// istream::sentry::sentry) were not previously marked with _LIBCPP_HIDE_FROM_ABI but should be to avoid symbol
545+
// visibility issues. However, adding the macro unconditionally would break the ABI on other platforms.
546+
//
547+
// Therefore, a dedicated macro _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 is introduced. This macro expands to
548+
// _LIBCPP_HIDE_FROM_ABI only when targeting MinGW, and to _LIBCPP_HIDE_FROM_ABI_AFTER_V1 on all other platforms.
549+
//
550+
// Going forward, whenever a new (static or non-static) member function or static data member is added to an
551+
// inner class within a class template that has explicit instantiation declaration, it must be annotated with
552+
// _LIBCPP_HIDE_FROM_ABI to ensure proper symbol visibility when targeting MinGW. Otherwise, the resulting DLL
553+
// will be unusable due to missing symbols.
554+
//
555+
// The underlying issue arises from how MinGW-GCC handles explicit instantiation declaration of a class template:
556+
//
557+
// - When exporting: 'extern template __declspec(dllexport) class TheTemplateClass<T>;'
558+
// allows exporting the outer template instantiation, but not its nested types (e.g., InnerClass).
559+
// note: this is just a declaration, needs a definition as `template class TheTemplateClass<T>;' at somewere.
560+
//
561+
// - When importing: 'extern template class TheTemplateClass<T>;'
562+
// causes MinGW-GCC to also try importing nested types such as TheTemplateClass<T>::InnerClass,
563+
// even if they were never exported. This leads to linker errors like:
564+
// 'undefined reference to TheTemplateClass<T>::InnerClass::...'
565+
//
566+
// This differs from Clang's historical behavior, which did not import nested classes implicitly.
567+
// However, to ensure ABI compatibility with the MinGW-GCC toolchain (commonly used in the MinGW ecosystem),
568+
// Clang will adopt this behavior as well.
569+
//
570+
// Note: As of this writing, Clang does not yet implement this behavior, since doing so would break libc++.
571+
# if defined(__MINGW32__) || defined(__CYGWIN__)
572+
# define _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
573+
# else
574+
# define _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 _LIBCPP_HIDE_FROM_ABI_AFTER_V1
575+
# endif
576+
533577
// TODO: Remove this workaround once we drop support for Clang 16
534578
# if __has_warning("-Wc++23-extensions")
535579
# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++23-extensions")

libcxx/include/__ostream/basic_ostream.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ class basic_ostream<_CharT, _Traits>::sentry {
186186
basic_ostream<_CharT, _Traits>& __os_;
187187

188188
public:
189-
explicit sentry(basic_ostream<_CharT, _Traits>& __os);
190-
~sentry();
189+
explicit inline _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 sentry(basic_ostream<_CharT, _Traits>& __os);
190+
inline _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1 ~sentry();
191191
sentry(const sentry&) = delete;
192192
sentry& operator=(const sentry&) = delete;
193193

libcxx/include/istream

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ class basic_istream<_CharT, _Traits>::sentry {
309309
bool __ok_;
310310

311311
public:
312-
explicit sentry(basic_istream<_CharT, _Traits>& __is, bool __noskipws = false);
312+
explicit inline _LIBCPP_HIDE_FROM_ABI_MINGW_OR_AFTER_V1
313+
sentry(basic_istream<_CharT, _Traits>& __is, bool __noskipws = false);
313314
// ~sentry() = default;
314315

315316
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const { return __ok_; }

0 commit comments

Comments
 (0)