diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 2a01df9de1..874f94288d 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -843,7 +843,7 @@ _NODISCARD int _Codecvt_do_length( enum _Codecvt_mode { _Consume_header = 4, _Generate_header = 2 }; -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT_UNLESS_CODECVT_ID_SATELLITE _CXX20_DEPRECATE_CODECVT_FACETS codecvt : public codecvt_base { // facet for converting between char16_t and UTF-8 byte sequences @@ -1141,7 +1141,7 @@ private: _Codecvt_mode _Mode; // default: _Consume_header }; -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT_UNLESS_CODECVT_ID_SATELLITE _CXX20_DEPRECATE_CODECVT_FACETS codecvt : public codecvt_base { // facet for converting between char32_t and UTF-8 byte sequences @@ -1395,7 +1395,7 @@ struct _NODISCARD _Codecvt_guard { } }; -template <> +extern "C++" template <> class codecvt : public codecvt_base { // facet for converting between UTF-16 and UTF-8 sequences public: @@ -1676,7 +1676,7 @@ protected: } }; -template <> +extern "C++" template <> class codecvt : public codecvt_base { // facet for converting between UTF-32 and UTF-8 sequences public: @@ -1919,7 +1919,7 @@ protected: }; #endif // defined(__cpp_char8_t) && !defined(_M_CEE_PURE) -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT codecvt : public codecvt_base { // facet for converting between wchar_t and char (_Byte) sequences public: @@ -2118,7 +2118,7 @@ private: }; #if defined(_NATIVE_WCHAR_T_DEFINED) && !_ENFORCE_FACET_SPECIALIZATIONS -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT codecvt : public codecvt_base { // facet for converting between unsigned short and char sequences public: @@ -2615,7 +2615,7 @@ locale::id ctype<_Elem>::id; #pragma clang diagnostic pop #endif // __clang__ -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT ctype : public ctype_base { // facet for classifying char elements, converting cases public: using _Elem = char; @@ -2805,7 +2805,7 @@ private: _Locinfo::_Ctypevec _Ctype; // information }; -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT ctype : public ctype_base { // facet for classifying wchar_t elements, converting cases public: @@ -3006,7 +3006,7 @@ private: }; #if defined(_NATIVE_WCHAR_T_DEFINED) && !_ENFORCE_FACET_SPECIALIZATIONS -template <> +extern "C++" template <> class _CRTIMP2_PURE_IMPORT ctype : public ctype_base { // facet for classifying unsigned short elements, converting cases public: diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 67d749bc80..3b2b04ed5c 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -772,9 +772,8 @@ __PURE_APPDOMAIN_GLOBAL locale::id time_put<_Elem, _OutIt>::id; #pragma clang diagnostic pop #endif // __clang__ -template -class _CRTIMP2_PURE_IMPORT time_put - : public locale::facet { // facet for converting encoded times to wchar_t text +extern "C++" template +class time_put : public locale::facet { // facet for converting encoded times to wchar_t text public: using _Elem = wchar_t; using char_type = _Elem; @@ -905,8 +904,8 @@ __PURE_APPDOMAIN_GLOBAL locale::id time_put::id; #if defined(_CRTBLD) -template -class _CRTIMP2_PURE_IMPORT time_put +extern "C++" template +class time_put : public locale::facet { // facet for converting encoded times to unsigned short text public: using _Elem = unsigned short; diff --git a/tests/std/include/test_header_units_and_modules.hpp b/tests/std/include/test_header_units_and_modules.hpp index 411bdb36f3..ee9d788780 100644 --- a/tests/std/include/test_header_units_and_modules.hpp +++ b/tests/std/include/test_header_units_and_modules.hpp @@ -1004,6 +1004,41 @@ void test_version() { #endif // ^^^ named modules ^^^ } +// VSO-1593165 "Standard Library Modules: time_put emits bogus error LNK2019: unresolved external symbol" +void test_VSO_1593165() { + using namespace std; + puts("Testing VSO-1593165."); + + // Originally from the Dev11_0494593_time_put_wchar_t test: + using Facet = time_put; + + const tm t = [] { + tm ret{}; + + ret.tm_sec = 57; + ret.tm_min = 42; + ret.tm_hour = 20; + ret.tm_mday = 28; + ret.tm_mon = 3; + ret.tm_year = 108; + ret.tm_wday = 1; + ret.tm_yday = 118; + ret.tm_isdst = 0; + + return ret; + }(); + + const locale l; + wstring s(15, L'x'); + wstringstream stream; + const wchar_t fill = L' '; + const wchar_t pattern[] = L"%Y.%m.%d"; + const wstring::iterator ret = use_facet(l).put(s.begin(), stream, fill, &t, begin(pattern), end(pattern)); + assert(ret == s.begin() + 11); + const wstring correct(L"2008.04.28\0xxxx", 15); + assert(s == correct); +} + void all_cpp_header_tests() { test_algorithm(); test_any(); @@ -1085,4 +1120,6 @@ void all_cpp_header_tests() { test_variant(); test_vector(); test_version(); + + test_VSO_1593165(); }