halyavin created this revision.
Fix the problem PR31516 <https://bugs.llvm.org/show_bug.cgi?id=31516> 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).
https://reviews.llvm.org/D40181
Files:
include/__locale
include/support/win32/locale_win32.h
src/support/win32/locale_win32.cpp
Index: src/support/win32/locale_win32.cpp
===================================================================
--- src/support/win32/locale_win32.cpp
+++ src/support/win32/locale_win32.cpp
@@ -18,23 +18,9 @@
// FIXME: base currently unused. Needs manual work to construct the new locale
locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
{
- return _create_locale( mask, locale );
+ return {_create_locale( LC_ALL, locale ), locale};
}
-locale_t uselocale( locale_t newloc )
-{
- locale_t old_locale = _get_current_locale();
- if ( newloc == NULL )
- return old_locale;
- // uselocale sets the thread's locale by definition, so unconditionally use thread-local locale
- _configthreadlocale( _ENABLE_PER_THREAD_LOCALE );
- // uselocale sets all categories
- // disable setting locale on Windows temporarily because the structure is opaque (PR31516)
- //setlocale( LC_ALL, newloc->locinfo->lc_category[LC_ALL].locale );
- // uselocale returns the old locale_t
- return old_locale;
-}
-
decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
{
#if defined(_LIBCPP_MSVCRT)
Index: include/support/win32/locale_win32.h
===================================================================
--- include/support/win32/locale_win32.h
+++ include/support/win32/locale_win32.h
@@ -14,6 +14,7 @@
#include <__config>
#include <stdio.h>
#include <xlocinfo.h> // _locale_t
+#include <__nullptr>
#define LC_COLLATE_MASK _M_COLLATE
#define LC_CTYPE_MASK _M_CTYPE
@@ -28,13 +29,77 @@
| LC_NUMERIC_MASK \
| LC_TIME_MASK )
-#define locale_t _locale_t
+class locale_t {
+public:
+ locale_t()
+ : __locale(nullptr), __locale_str(nullptr) {}
+ locale_t(std::nullptr_t)
+ : __locale(nullptr), __locale_str(nullptr) {}
+ locale_t(_locale_t __locale, const char* __locale_str)
+ : __locale(__locale), __locale_str(__locale_str) {}
+ friend bool operator==(const locale_t& __left, const locale_t& __right) {
+ return __left.__locale == __right.__locale;
+ }
+
+ friend bool operator==(const locale_t& __left, int __right) {
+ return __left.__locale == nullptr && __right == 0;
+ }
+
+ friend bool operator==(const locale_t& __left, nullptr_t) {
+ return __left.__locale == nullptr;
+ }
+
+ friend bool operator==(int __left, const locale_t& __right) {
+ return __left == 0 && nullptr == __right.__locale;
+ }
+
+ friend bool operator==(nullptr_t, const locale_t& __right) {
+ return nullptr == __right.__locale;
+ }
+
+ friend bool operator!=(const locale_t& __left, const locale_t& __right) {
+ return !(__left == __right);
+ }
+
+ friend bool operator!=(const locale_t& __left, int __right) {
+ return !(__left == __right);
+ }
+
+ friend bool operator!=(const locale_t& __left, nullptr_t __right) {
+ return !(__left == __right);
+ }
+
+ friend bool operator!=(int __left, const locale_t& __right) {
+ return !(__left == __right);
+ }
+
+ friend bool operator!=(nullptr_t __left, const locale_t& __right) {
+ return !(__left == __right);
+ }
+
+ operator bool() const {
+ return __locale != nullptr;
+ }
+
+ const char* __get_locale() const { return __locale_str; }
+
+ operator _locale_t() const {
+ return __locale;
+ }
+private:
+ _locale_t __locale;
+ const char* __locale_str;
+};
+
// Locale management functions
#define freelocale _free_locale
// FIXME: base currently unused. Needs manual work to construct the new locale
locale_t newlocale( int mask, const char * locale, locale_t base );
-locale_t uselocale( locale_t newloc );
+// uselocale can't be implemented on Windows because Windows allows partial modification
+// of thread-local locale and so _get_current_locale() returns a copy while uselocale does
+// not create any copies.
+// We can still implement raii even without uselocale though.
lconv *localeconv_l( locale_t loc );
Index: include/__locale
===================================================================
--- include/__locale
+++ include/__locale
@@ -49,7 +49,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#if !defined(_LIBCPP_LOCALE__L_EXTENSIONS) || defined(_LIBCPP_MSVCRT)
+#if !defined(_LIBCPP_LOCALE__L_EXTENSIONS)
struct __libcpp_locale_guard {
_LIBCPP_INLINE_VISIBILITY
__libcpp_locale_guard(locale_t& __loc) : __old_loc_(uselocale(__loc)) {}
@@ -65,6 +65,30 @@
__libcpp_locale_guard(__libcpp_locale_guard const&);
__libcpp_locale_guard& operator=(__libcpp_locale_guard const&);
};
+#elif defined(_LIBCPP_MSVCRT)
+struct __libcpp_locale_guard {
+ __libcpp_locale_guard(const locale_t& __l) :
+ __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)),
+ __locale_str{
+ setlocale(LC_COLLATE, __l.__get_locale()),
+ setlocale(LC_CTYPE, __l.__get_locale()),
+ setlocale(LC_MONETARY, __l.__get_locale()),
+ setlocale(LC_NUMERIC, __l.__get_locale()),
+ setlocale(LC_TIME, __l.__get_locale())
+ // LC_MESSAGES is not supported on Windows.
+ }
+ {}
+ ~__libcpp_locale_guard() {
+ setlocale(LC_COLLATE, __locale_str[0]);
+ setlocale(LC_CTYPE, __locale_str[1]);
+ setlocale(LC_MONETARY, __locale_str[2]);
+ setlocale(LC_NUMERIC, __locale_str[3]);
+ setlocale(LC_TIME, __locale_str[4]);
+ _configthreadlocale(__status);
+ }
+ int __status;
+ char* __locale_str[5];
+};
#endif
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits