]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix effects of combining locales [PR108323]
authorJonathan Wakely <jwakely@redhat.com>
Tue, 30 Jan 2024 14:48:28 +0000 (14:48 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 22 May 2024 22:10:05 +0000 (23:10 +0100)
This fixes a bug in locale::combine where we fail to meet the standard's
requirement that the result is unnamed. It also implements two library
issues related to the names of combined locales (2295 and 3676).

libstdc++-v3/ChangeLog:

PR libstdc++/108323
* include/bits/locale_classes.tcc (locale(const locale&, Facet*)):
Return a copy of the first argument when the facet pointer is
null, as per LWG 2295.
(locale::combine): Ensure the result is unnamed.
* src/c++11/localename.cc (_M_replace_categories): Ignore
whether the second locale has a name when cat == none, as per
LWG 3676.
* src/c++98/locale.cc (_M_install_facet): Use __builtin_expect
to predict that the facet pointer is non-null.
* testsuite/22_locale/locale/cons/names.cc: New test.

libstdc++-v3/include/bits/locale_classes.tcc
libstdc++-v3/src/c++11/localename.cc
libstdc++-v3/src/c++98/locale.cc
libstdc++-v3/testsuite/22_locale/locale/cons/names.cc [new file with mode: 0644]

index 63097582decfe8c016933624a3fb7f6a99549a97..00eeb7dd9f8951c78e0d229ba509658eda6971a9 100644 (file)
@@ -44,6 +44,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     locale::
     locale(const locale& __other, _Facet* __f)
     {
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 2295. Locale name when the provided Facet is a nullptr
+      if (__builtin_expect(!__f, 0))
+       {
+         _M_impl = __other._M_impl;
+         _M_impl->_M_add_reference();
+         return;
+       }
+
       _M_impl = new _Impl(*__other._M_impl, 1);
 
       __try
@@ -72,6 +81,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          __tmp->_M_remove_reference();
          __throw_exception_again;
        }
+      delete[] __tmp->_M_names[0];
+      __tmp->_M_names[0] = 0;   // Unnamed.
       return locale(__tmp);
     }
 
@@ -163,7 +174,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   */
   template<typename _Facet>
     inline bool
-    has_facet(const locale& __loc) throw()
+    has_facet(const locale& __loc) _GLIBCXX_USE_NOEXCEPT
     {
 #if __cplusplus >= 201103L
       static_assert(__is_base_of(locale::facet, _Facet),
index cde94ec6e19f60ffb91de6137d7d9126f3f8a32f..909cf4c66d346f8116930b0321caf57b519bb3fd 100644 (file)
@@ -326,7 +326,9 @@ const int num_facets = (
   _M_replace_categories(const _Impl* __imp, category __cat)
   {
     category __mask = 1;
-    if (!_M_names[0] || !__imp->_M_names[0])
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 3676. Name of locale composed using std::locale::none
+    if (!_M_names[0] || (__cat != none && !__imp->_M_names[0]))
       {
        if (_M_names[0])
          {
index 3749408115ea940611afe519efe83060e84aaa38..0e7533e1e1525cf3258329414df6944c080691d8 100644 (file)
@@ -323,7 +323,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   locale::_Impl::
   _M_install_facet(const locale::id* __idp, const facet* __fp)
   {
-    if (__fp)
+    if (__builtin_expect(__fp != 0, 1))
       {
        size_t __index = __idp->_M_id();
 
diff --git a/libstdc++-v3/testsuite/22_locale/locale/cons/names.cc b/libstdc++-v3/testsuite/22_locale/locale/cons/names.cc
new file mode 100644 (file)
index 0000000..2a9cfe4
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do run }
+
+#include <locale>
+#include <testsuite_hooks.h>
+
+void
+test_pr108323()
+{
+  std::locale named = std::locale::classic();
+  std::locale unnamed = named.combine<std::ctype<char> >(named);
+
+  // Bug libstdc++/108323 - combine does not change the locale name
+  VERIFY( unnamed.name() == "*" );
+}
+
+void
+test_lwg2295()
+{
+  std::locale named = std::locale::classic();
+  std::locale unnamed(named, &std::use_facet<std::ctype<char> >(named));
+  VERIFY( unnamed.name() == "*" );
+
+  // LWG 2295. Locale name when the provided Facet is a nullptr
+  std::locale loc(named, (std::ctype<char>*)0);
+  VERIFY( loc.name() != "*" );
+  VERIFY( loc.name() == named.name() );
+}
+
+void
+test_lwg3676()
+{
+  std::locale named = std::locale::classic();
+  std::locale unnamed = named.combine<std::ctype<char> >(named);
+  std::locale combo;
+
+  // LWG 3676. Name of locale composed using std::locale::none
+
+  combo = std::locale(named, named, std::locale::numeric);
+  VERIFY( combo.name() != "*" );
+  combo = std::locale(named, named, std::locale::none);
+  VERIFY( combo.name() != "*" );
+  combo = std::locale(named, unnamed, std::locale::numeric);
+  VERIFY( combo.name() == "*" );
+  combo = std::locale(named, unnamed, std::locale::none);
+  VERIFY( combo.name() != "*" );
+  combo = std::locale(unnamed, named, std::locale::numeric);
+  VERIFY( combo.name() == "*" );
+  combo = std::locale(unnamed, named, std::locale::none);
+  VERIFY( combo.name() == "*" );
+  combo = std::locale(unnamed, unnamed, std::locale::numeric);
+  VERIFY( combo.name() == "*" );
+  combo = std::locale(unnamed, unnamed, std::locale::none);
+  VERIFY( combo.name() == "*" );
+}
+
+int main()
+{
+  test_pr108323();
+  test_lwg2295();
+  test_lwg3676();
+}