diff --git a/stl/inc/locale b/stl/inc/locale index 73f075b2271..41963efa509 100644 --- a/stl/inc/locale +++ b/stl/inc/locale @@ -22,6 +22,78 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +template +int __CRTDECL _LStrcoll(const _Elem* _First1, const _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, + const _Locinfo::_Collvec*) { // perform locale-specific comparison of _Elem sequences + for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, ++_First2) { + if (*_First1 < *_First2) { + return -1; // [_First1, _Last1) < [_First2, _Last2) + } else if (*_First2 < *_First1) { + return +1; // [_First1, _Last1) > [_First2, _Last2) + } + } + + return _First2 != _Last2 ? -1 : _First1 != _Last1 ? +1 : 0; +} + +template <> +inline int __CRTDECL _LStrcoll(const char* _First1, const char* _Last1, const char* _First2, const char* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of char sequences + return _Strcoll(_First1, _Last1, _First2, _Last2, _Vector); +} + +template <> +inline int __CRTDECL _LStrcoll(const wchar_t* _First1, const wchar_t* _Last1, const wchar_t* _First2, + const wchar_t* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of wchar_t sequences + return _Wcscoll(_First1, _Last1, _First2, _Last2, _Vector); +} + +#ifdef _CRTBLD +template <> +inline int __CRTDECL _LStrcoll(const unsigned short* _First1, const unsigned short* _Last1, + const unsigned short* _First2, const unsigned short* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of unsigned short sequences + return _Wcscoll(reinterpret_cast(_First1), reinterpret_cast(_Last1), + reinterpret_cast(_First2), reinterpret_cast(_Last2), _Vector); +} +#endif // defined(_CRTBLD) + +template +size_t __CRTDECL _LStrxfrm(_Elem* _First1, _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, + const _Locinfo::_Collvec*) { // perform locale-specific transform of _Elems [_First1, _Last1) + const ptrdiff_t _Count = _Last2 - _First2; + if (_Count <= _Last1 - _First1) { + _CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem)); + } + + return _Count; +} + +template <> +inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return) char* _First1, + _In_z_ char* _Last1, const char* _First2, const char* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of chars [_First1, _Last1) + return _Strxfrm(_First1, _Last1, _First2, _Last2, _Vector); +} + +template <> +inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return) wchar_t* _First1, + _In_z_ wchar_t* _Last1, const wchar_t* _First2, const wchar_t* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of wchar_ts [_First1, _Last1) + return _Wcsxfrm(_First1, _Last1, _First2, _Last2, _Vector); +} + +#ifdef _CRTBLD +template <> +inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return) unsigned short* _First1, + _In_z_ unsigned short* _Last1, const unsigned short* _First2, const unsigned short* _Last2, + const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of unsigned shorts [_First1, _Last1) + return _Wcsxfrm(reinterpret_cast(_First1), reinterpret_cast(_Last1), + reinterpret_cast(_First2), reinterpret_cast(_Last2), _Vector); +} +#endif // defined(_CRTBLD) + _EXPORT_STD template class collate : public locale::facet { // facet for ordering sequences of elements public: diff --git a/stl/inc/xlocinfo b/stl/inc/xlocinfo index 80487ea2f33..054c2524fa6 100644 --- a/stl/inc/xlocinfo +++ b/stl/inc/xlocinfo @@ -385,58 +385,6 @@ private: _Yarn _Oldlocname; // old locale name to revert to on destruction _Yarn _Newlocname; // new locale name for this object }; - -template -int __CRTDECL _LStrcoll(const _Elem* _First1, const _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, - const _Locinfo::_Collvec*) { // perform locale-specific comparison of _Elem sequences - for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, ++_First2) { - if (*_First1 < *_First2) { - return -1; // [_First1, _Last1) < [_First2, _Last2) - } else if (*_First2 < *_First1) { - return +1; // [_First1, _Last1) > [_First2, _Last2) - } - } - - return _First2 != _Last2 ? -1 : _First1 != _Last1 ? +1 : 0; -} - -template <> -inline int __CRTDECL _LStrcoll(const char* _First1, const char* _Last1, const char* _First2, const char* _Last2, - const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of char sequences - return _Strcoll(_First1, _Last1, _First2, _Last2, _Vector); -} - -template <> -inline int __CRTDECL _LStrcoll(const wchar_t* _First1, const wchar_t* _Last1, const wchar_t* _First2, - const wchar_t* _Last2, - const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of wchar_t sequences - return _Wcscoll(_First1, _Last1, _First2, _Last2, _Vector); -} - -template -size_t __CRTDECL _LStrxfrm(_Elem* _First1, _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, - const _Locinfo::_Collvec*) { // perform locale-specific transform of _Elems [_First1, _Last1) - const ptrdiff_t _Count = _Last2 - _First2; - if (_Count <= _Last1 - _First1) { - _CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem)); - } - - return _Count; -} - -template <> -inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return) char* _First1, - _In_z_ char* _Last1, const char* _First2, const char* _Last2, - const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of chars [_First1, _Last1) - return _Strxfrm(_First1, _Last1, _First2, _Last2, _Vector); -} - -template <> -inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return) wchar_t* _First1, - _In_z_ wchar_t* _Last1, const wchar_t* _First2, const wchar_t* _Last2, - const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of wchar_ts [_First1, _Last1) - return _Wcsxfrm(_First1, _Last1, _First2, _Last2, _Vector); -} _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS diff --git a/tests/std/test.lst b/tests/std/test.lst index 292e4255c97..0cef6ce01d8 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -256,6 +256,7 @@ tests\GH_004929_internal_tag_constructors tests\GH_004930_char_traits_user_specialization tests\GH_005090_stl_hardening tests\GH_005204_regex_collating_ranges +tests\GH_005236_collate_facet tests\GH_005244_regex_escape_sequences tests\GH_005315_destructor_tombstones tests\LWG2381_num_get_floating_point diff --git a/tests/std/tests/GH_005204_regex_collating_ranges/test.cpp b/tests/std/tests/GH_005204_regex_collating_ranges/test.cpp index afa5b36d162..fcb5efeadf5 100644 --- a/tests/std/tests/GH_005204_regex_collating_ranges/test.cpp +++ b/tests/std/tests/GH_005204_regex_collating_ranges/test.cpp @@ -10,22 +10,16 @@ #include // skip collation tests when linking to the DLL in case of -// * undefined _NATIVE_WCHAR_T_DEFINED due to GH-5236 -// * _ITERATOR_DEBUG_LEVEL mismatch between code and linked DLL +// _ITERATOR_DEBUG_LEVEL mismatch between code and linked DLL #ifdef _DEBUG #define DEFAULT_IDL_SETTING 2 #else #define DEFAULT_IDL_SETTING 0 #endif -#ifdef _DLL -#ifndef _NATIVE_WCHAR_T_DEFINED // TRANSITION, GH-212 or GH-5236 +#if defined(_DLL) && _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING #define SKIP_COLLATE_TESTS -#elif _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING -#define SKIP_COLLATE_TESTS -#endif // !defined(_NATIVE_WCHAR_T_DEFINED) || _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING -#endif // defined(_DLL) - +#endif // defined(_DLL) && _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING using namespace std; using namespace std::regex_constants; diff --git a/tests/std/tests/GH_005236_collate_facet/env.lst b/tests/std/tests/GH_005236_collate_facet/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_005236_collate_facet/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_005236_collate_facet/test.cpp b/tests/std/tests/GH_005236_collate_facet/test.cpp new file mode 100644 index 00000000000..a54c301585b --- /dev/null +++ b/tests/std/tests/GH_005236_collate_facet/test.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +// skip collate::transform() tests when linking to the DLL in case of +// _ITERATOR_DEBUG_LEVEL mismatch between code and linked DLL +#ifdef _DEBUG +#define DEFAULT_IDL_SETTING 2 +#else +#define DEFAULT_IDL_SETTING 0 +#endif + +#if defined(_DLL) && _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING +#define SKIP_COLLATE_TRANSFORM_TESTS +#endif // defined(_DLL) && _ITERATOR_DEBUG_LEVEL != DEFAULT_IDL_SETTING + +using namespace std; + +// GH-5236 "std::collate does not respect collation order when compiled with /MD(d) /Zc:wchar_t-" +void test_gh_5236() { + const wchar_t Ue = L'\u00DC'; // U+00DC LATIN CAPITAL LETTER U WITH DIARESIS + const wchar_t U = L'U'; + const wchar_t V = L'V'; + + // German phonebook order: "U+00DC" is sorted between U and V in collation order + const locale loc("de-DE_phoneb"); + const auto& coll = use_facet>(loc); + + assert(coll.compare(&U, &U + 1, &Ue, &Ue + 1) < 0); + assert(coll.compare(&V, &V + 1, &Ue, &Ue + 1) > 0); + +#ifndef SKIP_COLLATE_TRANSFORM_TESTS + assert(coll.transform(&U, &U + 1) < coll.transform(&Ue, &Ue + 1)); + assert(coll.transform(&V, &V + 1) > coll.transform(&Ue, &Ue + 1)); +#endif // !defined(SKIP_COLLATE_TRANSFORM_TESTS) +} + +int main() { + test_gh_5236(); +} diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index 284e238b141..23fb0ef0f53 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -810,7 +810,7 @@ void limits_test() { void locale_test() { char c{}; locale loc{}; - // need all collates to instantiate xlocinfo _Lstrcoll and _Lstrxfrm + // need all collates to instantiate _Lstrcoll and _Lstrxfrm auto cc = has_facet>(loc); auto cw = has_facet>(loc); auto cbnc = has_facet>(loc);