This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] Allow to set locale on Windows.
ClosedPublic

Authored by halyavin on Nov 17 2017, 9:34 AM.

Details

Summary

Fix the problem PR31516 with setting locale on Windows by wrapping _locale_t with a pointer-like class.

Reduces 74 test failures in std/localization test suite to 47 test failures (on llvm clang, Visual Studio 2015). Number of test failures doesn't depend on the platform (x86 or x64).

Diff Detail

Repository
rL LLVM

Event Timeline

halyavin created this revision.Nov 17 2017, 9:34 AM
EricWF accepted this revision.Nov 20 2017, 12:06 PM

This LGTM. I would love if another party interested in Windows could review it though.

This revision is now accepted and ready to land.Nov 20 2017, 12:06 PM

This LGTM. I would love if another party interested in Windows could review it though.

I can test this in a MinGW context and see if what it uses happens to be available there or not.

In order to make this work with MinGW (more or less), I had to change the _LIBCPP_MSVCRT into _LIBCPP_MSVCRT_LIKE both in include/__locale and in include/__config (where _LIBCPP_LOCALE__L_EXTENSIONS is defined). Normal mingw that uses msvcrt.dll doesn't have per-thread locales so it won't really work in any case (but I think it does define some sort of dummy functions that at least will allow it to build). Nowadays, mingw can be built to target ucrtbase.dll as well though, and there it should be possible to make it work just like for MSVC although it might need some patches.

include/__locale
72 ↗(On Diff #123360)

This syntax only seems to work if the code using this is built in C++11 mode; this breaks building C++98 code.

include/support/win32/locale_win32.h
57 ↗(On Diff #123360)

In my testing, I had to change all these nullptr_t into std::nullptr_t in order to build it successfully.

compnerd accepted this revision.Nov 20 2017, 4:40 PM
halyavin updated this revision to Diff 123921.Nov 22 2017, 5:39 AM

Fixed problem with C++98, added std for nullptr_t and switched on _l functions for MinGW.

halyavin marked 2 inline comments as done.Nov 22 2017, 5:41 AM

(but I think it does define some sort of dummy functions that at least will allow it to build)

Looked into MinGW-w64 sources and this is indeed the case. _configthreadlocale will return -1 and will not do anything.

halyavin updated this revision to Diff 123923.Nov 22 2017, 5:47 AM
mstorsjo accepted this revision.Nov 22 2017, 11:51 AM

LGTM, thanks for updating it!

@EricWF, could you please commit this change?

This revision was automatically updated to reflect the committed changes.

I'm not be able to build libcxx with 64-bit mingw-w64 due to this commit.
Have error like:

[ 10%] Building CXX object projects/libcxx/lib/CMakeFiles/cxx_objects.dir/__/src/algorithm.cpp.obj
In file included from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ctype.h:39:0,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cctype:39,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cwctype:54,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cwchar:107,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/string:481,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/random:1645,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/src/algorithm.cpp:11:
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale: In static member function 'static void std::__1::__num_put<_CharT>::__widen_and_group_float(char*, char*, char*, _CharT*, _CharT*&, _CharT*&, const std::__1::locale&)':
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:150:20: error: ambiguous overload for 'operator!=' (operand types are 'locale_t' and 'long long int')
 #define isxdigit_l _isxdigit_l
                    ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1198:18: note: in expansion of macro 'isxdigit_l'
             if (!isxdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:150:20: note: candidate: operator!=(int, long long int) <built-in>
 #define isxdigit_l _isxdigit_l
                    ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1198:18: note: in expansion of macro 'isxdigit_l'
             if (!isxdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:150:20: note: candidate: operator!=(_locale_t {aka localeinfo_struct*}, _locale_t {aka localeinfo_struct*}) <built-in>
 #define isxdigit_l _isxdigit_l
                    ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1198:18: note: in expansion of macro 'isxdigit_l'
             if (!isxdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~~
In file included from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/__locale:23:0,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ios:216,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ostream:138,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/istream:163,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/random:1646,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/src/algorithm.cpp:11:
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:73:17: note: candidate: bool operator!=(int, const locale_t&)
     friend bool operator!=(int __left, const locale_t& __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:69:17: note: candidate: bool operator!=(const locale_t&, std::nullptr_t)
     friend bool operator!=(const locale_t& __left, std::nullptr_t __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:65:17: note: candidate: bool operator!=(const locale_t&, int)
     friend bool operator!=(const locale_t& __left, int __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:61:17: note: candidate: bool operator!=(const locale_t&, const locale_t&)
     friend bool operator!=(const locale_t& __left, const locale_t& __right) {
                 ^~~~~~~~
In file included from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ctype.h:39:0,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cctype:39,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cwctype:54,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/cwchar:107,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/string:481,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/random:1645,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/src/algorithm.cpp:11:
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:149:19: error: ambiguous overload for 'operator!=' (operand types are 'locale_t' and 'long long int')
 #define isdigit_l _isdigit_l
                   ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1204:18: note: in expansion of macro 'isdigit_l'
             if (!isdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:149:19: note: candidate: operator!=(int, long long int) <built-in>
 #define isdigit_l _isdigit_l
                   ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1204:18: note: in expansion of macro 'isdigit_l'
             if (!isdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:149:19: note: candidate: operator!=(_locale_t {aka localeinfo_struct*}, _locale_t {aka localeinfo_struct*}) <built-in>
 #define isdigit_l _isdigit_l
                   ^
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/locale:1204:18: note: in expansion of macro 'isdigit_l'
             if (!isdigit_l(*__ns, _LIBCPP_GET_C_LOCALE))
                  ^~~~~~~~~
In file included from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/__locale:23:0,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ios:216,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/ostream:138,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/istream:163,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/random:1646,
                 from C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/src/algorithm.cpp:11:
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:73:17: note: candidate: bool operator!=(int, const locale_t&)
     friend bool operator!=(int __left, const locale_t& __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:69:17: note: candidate: bool operator!=(const locale_t&, std::nullptr_t)
     friend bool operator!=(const locale_t& __left, std::nullptr_t __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:65:17: note: candidate: bool operator!=(const locale_t&, int)
     friend bool operator!=(const locale_t& __left, int __right) {
                 ^~~~~~~~
C:/repo/mingw-w64-clang/src/llvm-6.0.0.src/projects/libcxx/include/support/win32/locale_win32.h:61:17: note: candidate: bool operator!=(const locale_t&, const locale_t&)
     friend bool operator!=(const locale_t& __left, const locale_t& __right) {
                 ^~~~~~~~
make[2]: *** [projects/libcxx/lib/CMakeFiles/cxx_objects.dir/build.make:63: projects/libcxx/lib/CMakeFiles/cxx_objects.dir/__/src/algorithm.cpp.obj] Ошибка 1
make[1]: *** [CMakeFiles/Makefile2:11083: projects/libcxx/lib/CMakeFiles/cxx_objects.dir/all] Ошибка 2

I have a bug report - https://bugs.llvm.org/show_bug.cgi?id=41131 - that says that we can reduce the number of calls in __libcpp_locale_guard from 10 to 2 by calling:
setlocale(LC_ALL, ...) . Was this considered when this patch was created?

Herald added a project: Restricted Project. · View Herald TranscriptMar 18 2019, 5:02 PM

Yes, I considered it. But Microsoft documentation is not clear whether it will work or not for restoring inconsistent locales. The documentation shows how to save inconsistent locales with LC_ALL but doesn't provide an example for restoring them.