public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Fix effects of combining locales [PR108323]
@ 2024-05-22 22:33 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2024-05-22 22:33 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested x86_64-linux. Pushed to trunk.

-- >8 --

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  | 13 +++-
 libstdc++-v3/src/c++11/localename.cc          |  4 +-
 libstdc++-v3/src/c++98/locale.cc              |  2 +-
 .../testsuite/22_locale/locale/cons/names.cc  | 61 +++++++++++++++++++
 4 files changed, 77 insertions(+), 3 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/22_locale/locale/cons/names.cc

diff --git a/libstdc++-v3/include/bits/locale_classes.tcc b/libstdc++-v3/include/bits/locale_classes.tcc
index 63097582dec..00eeb7dd9f8 100644
--- a/libstdc++-v3/include/bits/locale_classes.tcc
+++ b/libstdc++-v3/include/bits/locale_classes.tcc
@@ -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),
diff --git a/libstdc++-v3/src/c++11/localename.cc b/libstdc++-v3/src/c++11/localename.cc
index cde94ec6e19..909cf4c66d3 100644
--- a/libstdc++-v3/src/c++11/localename.cc
+++ b/libstdc++-v3/src/c++11/localename.cc
@@ -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])
 	  {
diff --git a/libstdc++-v3/src/c++98/locale.cc b/libstdc++-v3/src/c++98/locale.cc
index 3749408115e..0e7533e1e15 100644
--- a/libstdc++-v3/src/c++98/locale.cc
+++ b/libstdc++-v3/src/c++98/locale.cc
@@ -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
index 00000000000..2a9cfe4c14d
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/locale/cons/names.cc
@@ -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();
+}
-- 
2.45.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-05-22 22:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-22 22:33 [committed] libstdc++: Fix effects of combining locales [PR108323] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).