[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
This commit is contained in:
Shoaib Meenai 2016-09-19 18:29:07 +00:00
parent 1197a1612d
commit 190994e435
5 changed files with 85 additions and 56 deletions

View File

@ -71,6 +71,26 @@ Visibility Macros
However since `_LIBCPP_TYPE_VIS_ONLY` is the same as `_LIBCPP_TYPE_VIS` the
visibility is already correct. The macro has an empty definition with GCC.
**Windows Behavior**: `extern template` and `dllexport` are fundamentally
incompatible *on a template class* on Windows; the former suppresses
instantiation, while the latter forces it. Specifying both on the same
declaration makes the template class be instantiated, which is not desirable
inside headers. This macro therefore expands to `dllimport` outside of libc++
but nothing inside of it (rather than expanding to `dllexport`); instead, the
explicit instantiations themselves are marked as exported. Note that this
applies *only* to extern template *classes*. Extern template *functions* obey
regular import/export semantics, and applying `dllexport` directly to the
extern template declaration is the correct thing to do for them.
**_LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS**
Mark the member functions, typeinfo, and vtable of an explicit instantiation
of a class template as being exported by the libc++ library. This attribute
must be specified on all template class explicit instantiations.
It is only necessary to mark the explicit instantiation itself (as opposed to
the extern template declaration) as exported on Windows, as discussed above.
On all other platforms, this macro has an empty definition.
**_LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY**
Mark a member function of a class template as hidden and inline except when
building the libc++ library where it marks the symbol as being exported by

View File

@ -551,15 +551,20 @@ namespace std {
// only really useful for a DLL. _LIBCPP_DLL should be a compiler builtin define ideally...
#if defined(_LIBCPP_DLL) && defined(cxx_EXPORTS)
# define _LIBCPP_DLL_VIS __declspec(dllexport)
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS _LIBCPP_DLL_VIS
#elif defined(_LIBCPP_DLL)
# define _LIBCPP_DLL_VIS __declspec(dllimport)
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
#else
# define _LIBCPP_DLL_VIS
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
#endif
#define _LIBCPP_TYPE_VIS _LIBCPP_DLL_VIS
#define _LIBCPP_FUNC_VIS _LIBCPP_DLL_VIS
#define _LIBCPP_EXCEPTION_ABI _LIBCPP_DLL_VIS
#define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
#define _LIBCPP_HIDDEN
#define _LIBCPP_TYPE_VIS_ONLY
#define _LIBCPP_FUNC_VIS_ONLY
@ -619,6 +624,10 @@ namespace std {
# endif
#endif
#ifndef _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
#endif
#ifndef _LIBCPP_INLINE_VISIBILITY
#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
#endif

View File

@ -25,19 +25,19 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template class basic_ios<char>;
template class basic_ios<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>;
template class basic_streambuf<char>;
template class basic_streambuf<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>;
template class basic_istream<char>;
template class basic_istream<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>;
template class basic_ostream<char>;
template class basic_ostream<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>;
template class basic_iostream<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>;
class _LIBCPP_HIDDEN __iostream_category
: public __do_message

View File

@ -6031,66 +6031,66 @@ void __throw_runtime_error(const char* msg)
#endif
}
template class collate<char>;
template class collate<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;
template class num_get<char>;
template class num_get<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;
template struct __num_get<char>;
template struct __num_get<wchar_t>;
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;
template class num_put<char>;
template class num_put<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;
template struct __num_put<char>;
template struct __num_put<wchar_t>;
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;
template class time_get<char>;
template class time_get<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;
template class time_get_byname<char>;
template class time_get_byname<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;
template class time_put<char>;
template class time_put<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;
template class time_put_byname<char>;
template class time_put_byname<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;
template class moneypunct<char, false>;
template class moneypunct<char, true>;
template class moneypunct<wchar_t, false>;
template class moneypunct<wchar_t, true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;
template class moneypunct_byname<char, false>;
template class moneypunct_byname<char, true>;
template class moneypunct_byname<wchar_t, false>;
template class moneypunct_byname<wchar_t, true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;
template class money_get<char>;
template class money_get<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;
template class __money_get<char>;
template class __money_get<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;
template class money_put<char>;
template class money_put<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;
template class __money_put<char>;
template class __money_put<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;
template class messages<char>;
template class messages<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;
template class messages_byname<char>;
template class messages_byname<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;
template class codecvt_byname<char, char, mbstate_t>;
template class codecvt_byname<wchar_t, char, mbstate_t>;
template class codecvt_byname<char16_t, char, mbstate_t>;
template class codecvt_byname<char32_t, char, mbstate_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
template class __vector_base_common<true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD

View File

@ -20,10 +20,10 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template class __basic_string_common<true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
template class basic_string<char>;
template class basic_string<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
template
string