smeenai created this revision. smeenai added reviewers: compnerd, EricWF, mclow.lists. smeenai added a subscriber: cfe-commits.
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. https://reviews.llvm.org/D24679 Files: docs/DesignDocs/VisibilityMacros.rst include/__config src/ios.cpp src/locale.cpp src/string.cpp
Index: src/string.cpp =================================================================== --- src/string.cpp +++ src/string.cpp @@ -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 Index: src/locale.cpp =================================================================== --- src/locale.cpp +++ src/locale.cpp @@ -6031,66 +6031,66 @@ #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 Index: src/ios.cpp =================================================================== --- src/ios.cpp +++ src/ios.cpp @@ -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 Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -547,15 +547,20 @@ // 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 @@ -609,6 +614,10 @@ # 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 Index: docs/DesignDocs/VisibilityMacros.rst =================================================================== --- docs/DesignDocs/VisibilityMacros.rst +++ docs/DesignDocs/VisibilityMacros.rst @@ -71,6 +71,26 @@ 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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits