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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to