[libcxx] r318902 - Allow to set locale on Windows.

Martin Storsjo via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 23 02:38:19 PST 2017


Author: mstorsjo
Date: Thu Nov 23 02:38:18 2017
New Revision: 318902

URL: http://llvm.org/viewvc/llvm-project?rev=318902&view=rev
Log:
Allow to set locale on Windows.

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).

Patch by Andrey Khalyavin.

Differential Revision: https://reviews.llvm.org/D40181

Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/__locale
    libcxx/trunk/include/support/win32/locale_win32.h
    libcxx/trunk/src/support/win32/locale_win32.cpp

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=318902&r1=318901&r2=318902&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Thu Nov 23 02:38:18 2017
@@ -890,7 +890,7 @@ template <unsigned> struct __static_asse
 #define _LIBCPP_NONUNIQUE_RTTI_BIT (1ULL << 63)
 #endif
 
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT) ||   \
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || \
     defined(__sun__) || defined(__NetBSD__) || defined(__CloudABI__)
 #define _LIBCPP_LOCALE__L_EXTENSIONS 1
 #endif

Modified: libcxx/trunk/include/__locale
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__locale?rev=318902&r1=318901&r2=318902&view=diff
==============================================================================
--- libcxx/trunk/include/__locale (original)
+++ libcxx/trunk/include/__locale Thu Nov 23 02:38:18 2017
@@ -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,32 @@ private:
   __libcpp_locale_guard(__libcpp_locale_guard const&);
   __libcpp_locale_guard& operator=(__libcpp_locale_guard const&);
 };
+#elif defined(_LIBCPP_MSVCRT_LIKE)
+struct __libcpp_locale_guard {
+    __libcpp_locale_guard(locale_t __l) :
+        __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)),
+        __locale_collate(setlocale(LC_COLLATE, __l.__get_locale())),
+        __locale_ctype(setlocale(LC_CTYPE, __l.__get_locale())),
+        __locale_monetary(setlocale(LC_MONETARY, __l.__get_locale())),
+        __locale_numeric(setlocale(LC_NUMERIC, __l.__get_locale())),
+        __locale_time(setlocale(LC_TIME, __l.__get_locale()))
+        // LC_MESSAGES is not supported on Windows.
+    {}
+    ~__libcpp_locale_guard() {
+        setlocale(LC_COLLATE, __locale_collate);
+        setlocale(LC_CTYPE, __locale_ctype);
+        setlocale(LC_MONETARY, __locale_monetary);
+        setlocale(LC_NUMERIC, __locale_numeric);
+        setlocale(LC_TIME, __locale_time);
+        _configthreadlocale(__status);
+    }
+    int __status;
+    char* __locale_collate;
+    char* __locale_ctype;
+    char* __locale_monetary;
+    char* __locale_numeric;
+    char* __locale_time;
+};
 #endif
 
 

Modified: libcxx/trunk/include/support/win32/locale_win32.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/support/win32/locale_win32.h?rev=318902&r1=318901&r2=318902&view=diff
==============================================================================
--- libcxx/trunk/include/support/win32/locale_win32.h (original)
+++ libcxx/trunk/include/support/win32/locale_win32.h Thu Nov 23 02:38:18 2017
@@ -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, std::nullptr_t) {
+        return __left.__locale == nullptr;
+    }
+
+    friend bool operator==(int __left, const locale_t& __right) {
+        return __left == 0 && nullptr == __right.__locale;
+    }
+
+    friend bool operator==(std::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, std::nullptr_t __right) {
+        return !(__left == __right);
+    }
+
+    friend bool operator!=(int __left, const locale_t& __right) {
+        return !(__left == __right);
+    }
+
+    friend bool operator!=(std::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 );

Modified: libcxx/trunk/src/support/win32/locale_win32.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/support/win32/locale_win32.cpp?rev=318902&r1=318901&r2=318902&view=diff
==============================================================================
--- libcxx/trunk/src/support/win32/locale_win32.cpp (original)
+++ libcxx/trunk/src/support/win32/locale_win32.cpp Thu Nov 23 02:38:18 2017
@@ -18,21 +18,7 @@ using std::__libcpp_locale_guard;
 // 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 );
-}
-
-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;
+    return {_create_locale( LC_ALL, locale ), locale};
 }
 
 decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )




More information about the cfe-commits mailing list