Skip to content

Commit 190994e

Browse files
committedSep 19, 2016
[libc++] Fix extern template visibility for Windows
On Windows, marking an `extern template class` declaration as exported actually forces an instantiation, which is not the desired behavior. Instead, the actual explicit instantiations need to be exported. Differential Revision: https://reviews.llvm.org/D24679 llvm-svn: 281925
1 parent 1197a16 commit 190994e

File tree

5 files changed

+85
-56
lines changed

5 files changed

+85
-56
lines changed
 

‎libcxx/docs/DesignDocs/VisibilityMacros.rst

+20
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,26 @@ Visibility Macros
7171
However since `_LIBCPP_TYPE_VIS_ONLY` is the same as `_LIBCPP_TYPE_VIS` the
7272
visibility is already correct. The macro has an empty definition with GCC.
7373

74+
**Windows Behavior**: `extern template` and `dllexport` are fundamentally
75+
incompatible *on a template class* on Windows; the former suppresses
76+
instantiation, while the latter forces it. Specifying both on the same
77+
declaration makes the template class be instantiated, which is not desirable
78+
inside headers. This macro therefore expands to `dllimport` outside of libc++
79+
but nothing inside of it (rather than expanding to `dllexport`); instead, the
80+
explicit instantiations themselves are marked as exported. Note that this
81+
applies *only* to extern template *classes*. Extern template *functions* obey
82+
regular import/export semantics, and applying `dllexport` directly to the
83+
extern template declaration is the correct thing to do for them.
84+
85+
**_LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS**
86+
Mark the member functions, typeinfo, and vtable of an explicit instantiation
87+
of a class template as being exported by the libc++ library. This attribute
88+
must be specified on all template class explicit instantiations.
89+
90+
It is only necessary to mark the explicit instantiation itself (as opposed to
91+
the extern template declaration) as exported on Windows, as discussed above.
92+
On all other platforms, this macro has an empty definition.
93+
7494
**_LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY**
7595
Mark a member function of a class template as hidden and inline except when
7696
building the libc++ library where it marks the symbol as being exported by

‎libcxx/include/__config

+10-1
Original file line numberDiff line numberDiff line change
@@ -551,15 +551,20 @@ namespace std {
551551
// only really useful for a DLL. _LIBCPP_DLL should be a compiler builtin define ideally...
552552
#if defined(_LIBCPP_DLL) && defined(cxx_EXPORTS)
553553
# define _LIBCPP_DLL_VIS __declspec(dllexport)
554+
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
555+
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS _LIBCPP_DLL_VIS
554556
#elif defined(_LIBCPP_DLL)
555557
# define _LIBCPP_DLL_VIS __declspec(dllimport)
558+
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
559+
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
556560
#else
557561
# define _LIBCPP_DLL_VIS
562+
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
563+
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
558564
#endif
559565
#define _LIBCPP_TYPE_VIS _LIBCPP_DLL_VIS
560566
#define _LIBCPP_FUNC_VIS _LIBCPP_DLL_VIS
561567
#define _LIBCPP_EXCEPTION_ABI _LIBCPP_DLL_VIS
562-
#define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
563568
#define _LIBCPP_HIDDEN
564569
#define _LIBCPP_TYPE_VIS_ONLY
565570
#define _LIBCPP_FUNC_VIS_ONLY
@@ -619,6 +624,10 @@ namespace std {
619624
# endif
620625
#endif
621626

627+
#ifndef _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
628+
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
629+
#endif
630+
622631
#ifndef _LIBCPP_INLINE_VISIBILITY
623632
#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
624633
#endif

‎libcxx/src/ios.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@
2525

2626
_LIBCPP_BEGIN_NAMESPACE_STD
2727

28-
template class basic_ios<char>;
29-
template class basic_ios<wchar_t>;
28+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>;
29+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>;
3030

31-
template class basic_streambuf<char>;
32-
template class basic_streambuf<wchar_t>;
31+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>;
32+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>;
3333

34-
template class basic_istream<char>;
35-
template class basic_istream<wchar_t>;
34+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>;
35+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>;
3636

37-
template class basic_ostream<char>;
38-
template class basic_ostream<wchar_t>;
37+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>;
38+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>;
3939

40-
template class basic_iostream<char>;
40+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>;
4141

4242
class _LIBCPP_HIDDEN __iostream_category
4343
: public __do_message

‎libcxx/src/locale.cpp

+43-43
Original file line numberDiff line numberDiff line change
@@ -6031,66 +6031,66 @@ void __throw_runtime_error(const char* msg)
60316031
#endif
60326032
}
60336033

6034-
template class collate<char>;
6035-
template class collate<wchar_t>;
6034+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
6035+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;
60366036

6037-
template class num_get<char>;
6038-
template class num_get<wchar_t>;
6037+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
6038+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;
60396039

6040-
template struct __num_get<char>;
6041-
template struct __num_get<wchar_t>;
6040+
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
6041+
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;
60426042

6043-
template class num_put<char>;
6044-
template class num_put<wchar_t>;
6043+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
6044+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;
60456045

6046-
template struct __num_put<char>;
6047-
template struct __num_put<wchar_t>;
6046+
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
6047+
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;
60486048

6049-
template class time_get<char>;
6050-
template class time_get<wchar_t>;
6049+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
6050+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;
60516051

6052-
template class time_get_byname<char>;
6053-
template class time_get_byname<wchar_t>;
6052+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
6053+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;
60546054

6055-
template class time_put<char>;
6056-
template class time_put<wchar_t>;
6055+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
6056+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;
60576057

6058-
template class time_put_byname<char>;
6059-
template class time_put_byname<wchar_t>;
6058+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
6059+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;
60606060

6061-
template class moneypunct<char, false>;
6062-
template class moneypunct<char, true>;
6063-
template class moneypunct<wchar_t, false>;
6064-
template class moneypunct<wchar_t, true>;
6061+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
6062+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
6063+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;
6064+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;
60656065

6066-
template class moneypunct_byname<char, false>;
6067-
template class moneypunct_byname<char, true>;
6068-
template class moneypunct_byname<wchar_t, false>;
6069-
template class moneypunct_byname<wchar_t, true>;
6066+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
6067+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
6068+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;
6069+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;
60706070

6071-
template class money_get<char>;
6072-
template class money_get<wchar_t>;
6071+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
6072+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;
60736073

6074-
template class __money_get<char>;
6075-
template class __money_get<wchar_t>;
6074+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
6075+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;
60766076

6077-
template class money_put<char>;
6078-
template class money_put<wchar_t>;
6077+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
6078+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;
60796079

6080-
template class __money_put<char>;
6081-
template class __money_put<wchar_t>;
6080+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
6081+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;
60826082

6083-
template class messages<char>;
6084-
template class messages<wchar_t>;
6083+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
6084+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;
60856085

6086-
template class messages_byname<char>;
6087-
template class messages_byname<wchar_t>;
6086+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
6087+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;
60886088

6089-
template class codecvt_byname<char, char, mbstate_t>;
6090-
template class codecvt_byname<wchar_t, char, mbstate_t>;
6091-
template class codecvt_byname<char16_t, char, mbstate_t>;
6092-
template class codecvt_byname<char32_t, char, mbstate_t>;
6089+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
6090+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;
6091+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
6092+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
60936093

6094-
template class __vector_base_common<true>;
6094+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
60956095

60966096
_LIBCPP_END_NAMESPACE_STD

‎libcxx/src/string.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
_LIBCPP_BEGIN_NAMESPACE_STD
2222

23-
template class __basic_string_common<true>;
23+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
2424

25-
template class basic_string<char>;
26-
template class basic_string<wchar_t>;
25+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
26+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
2727

2828
template
2929
string

0 commit comments

Comments
 (0)
Please sign in to comment.