[libcxx-commits] [libcxx] WIP - [libc++][string] P2587R3: `to_string` or not `to_string` (PR #78100)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 14 00:26:18 PDT 2025


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/78100

>From e93f15bd61afea3329a6e5cb8b446433ba45f23b Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 10 Jan 2024 15:55:44 +0200
Subject: [PATCH 1/6] [libc++][string] P2587R3: `to_string` or not `to_string`

---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +-
 libcxx/docs/Status/Cxx2cPapers.csv            |   2 +-
 libcxx/include/version                        |   2 +-
 libcxx/src/string.cpp                         |  21 ++-
 .../string.version.compile.pass.cpp           |  16 +--
 .../version.version.compile.pass.cpp          |  16 +--
 .../string.conversions/to_string.pass.cpp     | 131 +++++++++++++++++-
 .../string.conversions/to_wstring.pass.cpp    | 131 +++++++++++++++++-
 .../generate_feature_test_macro_components.py |   1 -
 9 files changed, 292 insertions(+), 30 deletions(-)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index dcf9838edd74b..9e8bd462357a4 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -498,7 +498,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_to_chars``                                     *unimplemented*
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_string``                                    *unimplemented*
+    ``__cpp_lib_to_string``                                    ``202306L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_tuple_like``                                   *unimplemented*
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 1436db6cf2b45..406314f493c7f 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -1,7 +1,7 @@
 "Paper #","Paper Name","Meeting","Status","First released version","Notes"
 "`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18",""
 "`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
-"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","",""
+"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","|Complete|","25",""
 "`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20",""
 "`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
 "`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
diff --git a/libcxx/include/version b/libcxx/include/version
index 63ead9fd5d29d..be6effd88fb9d 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -588,7 +588,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_text_encoding                        202306L
 # undef  __cpp_lib_to_chars
 // # define __cpp_lib_to_chars                             202306L
-// # define __cpp_lib_to_string                            202306L
+# define __cpp_lib_to_string                            202306L
 # undef  __cpp_lib_tuple_like
 // # define __cpp_lib_tuple_like                           202311L
 # undef  __cpp_lib_variant
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index e335639883dba..70afe14c4ccca 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -10,6 +10,7 @@
 #include <cerrno>
 #include <charconv>
 #include <cstdlib>
+#include <format>
 #include <limits>
 #include <stdexcept>
 #include <string>
@@ -372,14 +373,30 @@ wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
 #endif
 
+#if _LIBCPP_STD_VER >= 26
+
+string to_string(float val) { return std::format("{}", val); }
+string to_string(double val) { return std::format("{}", val); }
+string to_string(long double val) { return std::format("{}", val); }
+
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+wstring to_wstring(float val) { return std::format(L"{}", val); }
+wstring to_wstring(double val) { return std::format(L"{}", val); }
+wstring to_wstring(long double val) { return std::format(L"{}", val); }
+#  endif
+
+#else
+
 string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
 string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
 string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
 
-#if _LIBCPP_HAS_WIDE_CHARACTERS
+#  if _LIBCPP_HAS_WIDE_CHARACTERS
 wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
 wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
-#endif
+#  endif
+
+#endif // _LIBCPP_STD_VER >= 26
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
index 69a938edd1cb9..4007639759112 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
@@ -488,17 +488,11 @@
 #   error "__cpp_lib_string_view should have the value 202403L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_to_string
-#     error "__cpp_lib_to_string should be defined in c++26"
-#   endif
-#   if __cpp_lib_to_string != 202306L
-#     error "__cpp_lib_to_string should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_to_string
-#     error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_to_string
+#   error "__cpp_lib_to_string should be defined in c++26"
+# endif
+# if __cpp_lib_to_string != 202306L
+#   error "__cpp_lib_to_string should have the value 202306L in c++26"
 # endif
 
 #endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 1e4465d515e6b..275715f082855 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -8107,17 +8107,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_to_string
-#     error "__cpp_lib_to_string should be defined in c++26"
-#   endif
-#   if __cpp_lib_to_string != 202306L
-#     error "__cpp_lib_to_string should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_to_string
-#     error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_to_string
+#   error "__cpp_lib_to_string should be defined in c++26"
+# endif
+# if __cpp_lib_to_string != 202306L
+#   error "__cpp_lib_to_string should have the value 202306L in c++26"
 # endif
 
 # ifndef __cpp_lib_to_underlying
diff --git a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
index 4731a072e8910..87ab89c39ffe7 100644
--- a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
@@ -18,8 +18,9 @@
 // string to_string(double val);
 // string to_string(long double val);
 
-#include <string>
 #include <cassert>
+#include <format>
+#include <string>
 #include <limits>
 
 #include "parse_integer.h"
@@ -32,29 +33,44 @@ void test_signed() {
     assert(s.size() == 1);
     assert(s[s.size()] == 0);
     assert(s == "0");
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", T(0)));
+#endif
   }
   {
     std::string s = std::to_string(T(12345));
     assert(s.size() == 5);
     assert(s[s.size()] == 0);
     assert(s == "12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", T(12345)));
+#endif
   }
   {
     std::string s = std::to_string(T(-12345));
     assert(s.size() == 6);
     assert(s[s.size()] == 0);
     assert(s == "-12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", T(-12345)));
+#endif
   }
   {
     std::string s = std::to_string(std::numeric_limits<T>::max());
     assert(s.size() == std::numeric_limits<T>::digits10 + 1);
     T t = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::max());
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", std::numeric_limits<T>::max()));
+#endif
   }
   {
     std::string s = std::to_string(std::numeric_limits<T>::min());
     T t           = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::min());
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", std::numeric_limits<T>::min()));
+#endif
   }
 }
 
@@ -65,18 +81,27 @@ void test_unsigned() {
     assert(s.size() == 1);
     assert(s[s.size()] == 0);
     assert(s == "0");
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", T(0)));
+#endif
   }
   {
     std::string s = std::to_string(T(12345));
     assert(s.size() == 5);
     assert(s[s.size()] == 0);
     assert(s == "12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", T(12345)));
+#endif
   }
   {
     std::string s = std::to_string(std::numeric_limits<T>::max());
     assert(s.size() == std::numeric_limits<T>::digits10 + 1);
     T t = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::max());
+#if TEST_STD_VER >= 26
+    assert(s == std::format("{}", std::numeric_limits<T>::max()));
+#endif
   }
 }
 
@@ -84,24 +109,125 @@ template <class T>
 void test_float() {
   {
     std::string s = std::to_string(T(0));
+#if TEST_STD_VER < 26
     assert(s.size() == 8);
     assert(s[s.size()] == 0);
     assert(s == "0.000000");
+#else
+    std::string f = std::format("{}", T(0));
+    assert(s == f);
+    assert(s == "0");
+#endif
   }
   {
     std::string s = std::to_string(T(12345));
+#if TEST_STD_VER < 26
     assert(s.size() == 12);
     assert(s[s.size()] == 0);
     assert(s == "12345.000000");
+#else
+    std::string f = std::format("{}", T(12345));
+    assert(s == f);
+    assert(s == "12345");
+#endif
   }
   {
     std::string s = std::to_string(T(-12345));
+#if TEST_STD_VER < 26
     assert(s.size() == 13);
     assert(s[s.size()] == 0);
     assert(s == "-12345.000000");
+#else
+    std::string f = std::format("{}", T(-12345));
+    assert(s == f);
+    assert(s == "-12345");
+#endif
+  }
+
+#if TEST_STD_VER >= 26
+  {
+    std::string s = std::to_string(T(90.84));
+    std::string f = std::format("{}", T(90.84));
+    assert(s == f);
+    assert(s == "90.84");
   }
+  {
+    std::string s = std::to_string(T(-90.84));
+    std::string f = std::format("{}", T(-90.84));
+    assert(s == f);
+    assert(s == "-90.84");
+  }
+#endif
+}
+
+#if TEST_STD_VER >= 26
+
+template <class T>
+void test_float_with_locale(const char* locale, T inputValue, const char* expectedValue) {
+  setlocale(LC_ALL, locale);
+
+  std::string s = std::to_string(inputValue);
+  std::string f = std::format("{}", inputValue);
+  assert(s == f);
+  assert(s == expectedValue);
 }
 
+void test_float_with_locale() {
+  // Locale "C"
+
+  test_float_with_locale<float>("C", 0.9084, "0.9084");
+  test_float_with_locale<double>("C", 0.9084, "0.9084");
+  test_float_with_locale<long double>("C", 0.9084, "0.9084");
+
+  test_float_with_locale<float>("C", -0.9084, "-0.9084");
+  test_float_with_locale<double>("C", -0.9084, "-0.9084");
+  test_float_with_locale<long double>("C", -0.9084, "-0.9084");
+
+  test_float_with_locale<float>("C", 1e-7, "1e-07");
+  test_float_with_locale<double>("C", 1e-7, "1e-07");
+  test_float_with_locale<long double>("C", 1e-7, "1e-07");
+
+  test_float_with_locale<float>("C", -1e-7, "-1e-07");
+  test_float_with_locale<double>("C", -1e-7, "-1e-07");
+  test_float_with_locale<long double>("C", -1e-7, "-1e-07");
+
+  test_float_with_locale<float>("C", 1.7976931348623157e+308, "inf");
+  test_float_with_locale<double>("C", 1.7976931348623157e+308, "1.7976931348623157e+308");
+  test_float_with_locale<long double>("C", 1.7976931348623157e+308, "1.7976931348623157e+308");
+
+  test_float_with_locale<float>("C", -1.7976931348623157e+308, "-inf");
+  test_float_with_locale<double>("C", -1.7976931348623157e+308, "-1.7976931348623157e+308");
+  test_float_with_locale<long double>("C", -1.7976931348623157e+308, "-1.7976931348623157e+308");
+
+  // Locale "uk_UA.UTF-8"
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 0.9084, "0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", 0.9084, "0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", 0.9084, "0.9084");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -0.9084, "-0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", -0.9084, "-0.9084");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -0.9084, "-0.9084");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 1e-7, "1e-07");
+  test_float_with_locale<double>("uk_UA.UTF-8", 1e-7, "1e-07");
+  test_float_with_locale<long double>("uk_UA.UTF-8", 1e-7, "1e-07");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -1e-7, "-1e-07");
+  test_float_with_locale<double>("uk_UA.UTF-8", -1e-7, "-1e-07");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -1e-7, "-1e-07");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 1.7976931348623157e+308, "inf");
+  test_float_with_locale<double>("uk_UA.UTF-8", 1.7976931348623157e+308, "1.7976931348623157e+308");
+  test_float_with_locale<long double>("uk_UA.UTF-8", 1.7976931348623157e+308, "1.7976931348623157e+308");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -1.7976931348623157e+308, "-inf");
+  test_float_with_locale<double>("uk_UA.UTF-8", -1.7976931348623157e+308, "-1.7976931348623157e+308");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -1.7976931348623157e+308, "-1.7976931348623157e+308");
+}
+
+#endif
+
 int main(int, char**) {
   test_signed<int>();
   test_signed<long>();
@@ -112,6 +238,9 @@ int main(int, char**) {
   test_float<float>();
   test_float<double>();
   test_float<long double>();
+#if TEST_STD_VER >= 26
+  test_float_with_locale();
+#endif
 
   return 0;
 }
diff --git a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
index fff5ede848b57..6c3a5825c43aa 100644
--- a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
@@ -20,8 +20,9 @@
 // wstring to_wstring(double val);
 // wstring to_wstring(long double val);
 
-#include <string>
 #include <cassert>
+#include <format>
+#include <string>
 #include <limits>
 
 #include "parse_integer.h"
@@ -34,29 +35,44 @@ void test_signed() {
     assert(s.size() == 1);
     assert(s[s.size()] == 0);
     assert(s == L"0");
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(0)));
+#endif
   }
   {
     std::wstring s = std::to_wstring(T(12345));
     assert(s.size() == 5);
     assert(s[s.size()] == 0);
     assert(s == L"12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(12345)));
+#endif
   }
   {
     std::wstring s = std::to_wstring(T(-12345));
     assert(s.size() == 6);
     assert(s[s.size()] == 0);
     assert(s == L"-12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(-12345)));
+#endif
   }
   {
     std::wstring s = std::to_wstring(std::numeric_limits<T>::max());
     assert(s.size() == std::numeric_limits<T>::digits10 + 1);
     T t = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::max());
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(std::numeric_limits<T>::max())));
+#endif
   }
   {
     std::wstring s = std::to_wstring(std::numeric_limits<T>::min());
     T t            = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::min());
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(std::numeric_limits<T>::min())));
+#endif
   }
 }
 
@@ -67,18 +83,27 @@ void test_unsigned() {
     assert(s.size() == 1);
     assert(s[s.size()] == 0);
     assert(s == L"0");
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(0)));
+#endif
   }
   {
     std::wstring s = std::to_wstring(T(12345));
     assert(s.size() == 5);
     assert(s[s.size()] == 0);
     assert(s == L"12345");
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(12345)));
+#endif
   }
   {
     std::wstring s = std::to_wstring(std::numeric_limits<T>::max());
     assert(s.size() == std::numeric_limits<T>::digits10 + 1);
     T t = parse_integer<T>(s);
     assert(t == std::numeric_limits<T>::max());
+#if TEST_STD_VER >= 26
+    assert(s == std::format(L"{}", T(std::numeric_limits<T>::max())));
+#endif
   }
 }
 
@@ -86,24 +111,125 @@ template <class T>
 void test_float() {
   {
     std::wstring s = std::to_wstring(T(0));
+#if TEST_STD_VER < 26
     assert(s.size() == 8);
     assert(s[s.size()] == 0);
     assert(s == L"0.000000");
+#else
+    std::wstring f = std::format(L"{}", T(0));
+    assert(s == f);
+    assert(s == L"0");
+#endif
   }
   {
     std::wstring s = std::to_wstring(T(12345));
+#if TEST_STD_VER < 26
     assert(s.size() == 12);
     assert(s[s.size()] == 0);
     assert(s == L"12345.000000");
+#else
+    std::wstring f = std::format(L"{}", T(12345));
+    assert(s == f);
+    assert(s == L"12345");
+#endif
   }
   {
     std::wstring s = std::to_wstring(T(-12345));
+#if TEST_STD_VER < 26
     assert(s.size() == 13);
     assert(s[s.size()] == 0);
     assert(s == L"-12345.000000");
+#else
+    std::wstring f = std::format(L"{}", T(-12345));
+    assert(s == f);
+    assert(s == L"-12345");
+#endif
+  }
+
+#if TEST_STD_VER >= 26
+  {
+    std::wstring s = std::to_wstring(T(90.84));
+    std::wstring f = std::format(L"{}", T(90.84));
+    assert(s == f);
+    assert(s == L"90.84");
   }
+  {
+    std::wstring s = std::to_wstring(T(-90.84));
+    std::wstring f = std::format(L"{}", T(-90.84));
+    assert(s == f);
+    assert(s == L"-90.84");
+  }
+#endif
+}
+
+#if TEST_STD_VER >= 26
+
+template <class T>
+void test_float_with_locale(const char* locale, T inputValue, const wchar_t* expectedValue) {
+  setlocale(LC_ALL, locale);
+
+  std::wstring s = std::to_wstring(inputValue);
+  std::wstring f = std::format(L"{}", inputValue);
+  assert(s == f);
+  assert(s == expectedValue);
 }
 
+void test_float_with_locale() {
+  // Locale "C"
+
+  test_float_with_locale<float>("C", 0.9084, L"0.9084");
+  test_float_with_locale<double>("C", 0.9084, L"0.9084");
+  test_float_with_locale<long double>("C", 0.9084, L"0.9084");
+
+  test_float_with_locale<float>("C", -0.9084, L"-0.9084");
+  test_float_with_locale<double>("C", -0.9084, L"-0.9084");
+  test_float_with_locale<long double>("C", -0.9084, L"-0.9084");
+
+  test_float_with_locale<float>("C", 1e-7, L"1e-07");
+  test_float_with_locale<double>("C", 1e-7, L"1e-07");
+  test_float_with_locale<long double>("C", 1e-7, L"1e-07");
+
+  test_float_with_locale<float>("C", -1e-7, L"-1e-07");
+  test_float_with_locale<double>("C", -1e-7, L"-1e-07");
+  test_float_with_locale<long double>("C", -1e-7, L"-1e-07");
+
+  test_float_with_locale<float>("C", 1.7976931348623157e+308, L"inf");
+  test_float_with_locale<double>("C", 1.7976931348623157e+308, L"1.7976931348623157e+308");
+  test_float_with_locale<long double>("C", 1.7976931348623157e+308, L"1.7976931348623157e+308");
+
+  test_float_with_locale<float>("C", -1.7976931348623157e+308, L"-inf");
+  test_float_with_locale<double>("C", -1.7976931348623157e+308, L"-1.7976931348623157e+308");
+  test_float_with_locale<long double>("C", -1.7976931348623157e+308, L"-1.7976931348623157e+308");
+
+  // Locale "uk_UA.UTF-8"
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 0.9084, L"0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", 0.9084, L"0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", 0.9084, L"0.9084");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -0.9084, L"-0.9084");
+  test_float_with_locale<double>("uk_UA.UTF-8", -0.9084, L"-0.9084");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -0.9084, L"-0.9084");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 1e-7, L"1e-07");
+  test_float_with_locale<double>("uk_UA.UTF-8", 1e-7, L"1e-07");
+  test_float_with_locale<long double>("uk_UA.UTF-8", 1e-7, L"1e-07");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -1e-7, L"-1e-07");
+  test_float_with_locale<double>("uk_UA.UTF-8", -1e-7, L"-1e-07");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -1e-7, L"-1e-07");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", 1.7976931348623157e+308, L"inf");
+  test_float_with_locale<double>("uk_UA.UTF-8", 1.7976931348623157e+308, L"1.7976931348623157e+308");
+  test_float_with_locale<long double>("uk_UA.UTF-8", 1.7976931348623157e+308, L"1.7976931348623157e+308");
+
+  test_float_with_locale<float>("uk_UA.UTF-8", -1.7976931348623157e+308, L"-inf");
+  test_float_with_locale<double>("uk_UA.UTF-8", -1.7976931348623157e+308, L"-1.7976931348623157e+308");
+  test_float_with_locale<long double>("uk_UA.UTF-8", -1.7976931348623157e+308, L"-1.7976931348623157e+308");
+}
+
+#endif
+
 int main(int, char**) {
   test_signed<int>();
   test_signed<long>();
@@ -114,6 +240,9 @@ int main(int, char**) {
   test_float<float>();
   test_float<double>();
   test_float<long double>();
+#if TEST_STD_VER >= 26
+  test_float_with_locale();
+#endif
 
   return 0;
 }
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 8bf7633e985d5..deb72b54531ad 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1366,7 +1366,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_to_string",
             "values": {"c++26": 202306},  # P2587R3 to_string or not to_string
             "headers": ["string"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_to_underlying",

>From 64bfa401bcf9b55a7e92f860fe4acc28d57116e0 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 13 Mar 2025 15:13:01 +0200
Subject: [PATCH 2/6] Addressed review comments

---
 libcxx/include/string | 26 ++++++++++++++++++++++++++
 libcxx/src/string.cpp | 26 +++++++++++---------------
 2 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index ea9ba24084a3b..78c530a72b069 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3939,9 +3939,22 @@ _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val);
 _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val);
 _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val);
 _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val);
+
+#  if _LIBCPP_STD_VER >= 26
+inline namespace __cpp26 {
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(float __val);
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(double __val);
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(long double __val);
+
+_LIBCPP_HIDE_FROM_ABI inline string to_string(float __val) { return __to_string(__val); }
+_LIBCPP_HIDE_FROM_ABI inline string to_string(double __val) { return __to_string(__val); }
+_LIBCPP_HIDE_FROM_ABI inline string to_string(long double __val) { return __to_string(__val); }
+} // namespace __cpp26
+#  else
 _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val);
 _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val);
 _LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val);
+#  endif
 
 #  if _LIBCPP_HAS_WIDE_CHARACTERS
 _LIBCPP_EXPORTED_FROM_ABI int stoi(const wstring& __str, size_t* __idx = nullptr, int __base = 10);
@@ -3960,9 +3973,22 @@ _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val);
+
+#    if _LIBCPP_STD_VER >= 26
+inline namespace __cpp26 {
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(float __val);
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(double __val);
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(long double __val);
+
+_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(float __val) { return __to_wstring(__val); }
+_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(double __val) { return __to_wstring(__val); }
+_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(long double __val) { return __to_wstring(__val); }
+} // namespace __cpp26
+#    else
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val);
+#    endif
 #  endif // _LIBCPP_HAS_WIDE_CHARACTERS
 
 template <class _CharT, class _Traits, class _Allocator>
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 70afe14c4ccca..012d65ee60187 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -373,19 +373,17 @@ wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
 #endif
 
-#if _LIBCPP_STD_VER >= 26
-
-string to_string(float val) { return std::format("{}", val); }
-string to_string(double val) { return std::format("{}", val); }
-string to_string(long double val) { return std::format("{}", val); }
-
-#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-wstring to_wstring(float val) { return std::format(L"{}", val); }
-wstring to_wstring(double val) { return std::format(L"{}", val); }
-wstring to_wstring(long double val) { return std::format(L"{}", val); }
-#  endif
-
-#else
+namespace __cpp26 {
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(float __val) { return std::format("{}", __val); }
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(double __val) { return std::format("{}", __val); }
+_LIBCPP_EXPORTED_FROM_ABI string __to_string(long double __val) { return std::format("{}", __val); }
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(float __val) { return std::format(L"{}", __val); }
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(double __val) { return std::format(L"{}", __val); }
+_LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(long double __val) { return std::format(L"{}", __val); }
+#endif
+} // namespace __cpp26
 
 string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
 string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
@@ -397,6 +395,4 @@ wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string
 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
 #  endif
 
-#endif // _LIBCPP_STD_VER >= 26
-
 _LIBCPP_END_NAMESPACE_STD

>From 10d6666ed6f7f3db93d230508860cf60be2b7e87 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 13 Mar 2025 16:01:34 +0200
Subject: [PATCH 3/6] CI

---
 libcxx/include/string                                | 12 ++++++------
 ...-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist |  9 +++++++++
 ...nu.libcxxabi.v1.stable.noexceptions.nonew.abilist |  9 +++++++++
 libcxx/src/string.cpp                                |  4 ++--
 4 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 78c530a72b069..adfed77011997 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3946,9 +3946,9 @@ _LIBCPP_EXPORTED_FROM_ABI string __to_string(float __val);
 _LIBCPP_EXPORTED_FROM_ABI string __to_string(double __val);
 _LIBCPP_EXPORTED_FROM_ABI string __to_string(long double __val);
 
-_LIBCPP_HIDE_FROM_ABI inline string to_string(float __val) { return __to_string(__val); }
-_LIBCPP_HIDE_FROM_ABI inline string to_string(double __val) { return __to_string(__val); }
-_LIBCPP_HIDE_FROM_ABI inline string to_string(long double __val) { return __to_string(__val); }
+inline _LIBCPP_HIDE_FROM_ABI string to_string(float __val) { return std::__to_string(__val); }
+inline _LIBCPP_HIDE_FROM_ABI string to_string(double __val) { return std::__to_string(__val); }
+inline _LIBCPP_HIDE_FROM_ABI string to_string(long double __val) { return std::__to_string(__val); }
 } // namespace __cpp26
 #  else
 _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val);
@@ -3980,9 +3980,9 @@ _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(float __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(double __val);
 _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(long double __val);
 
-_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(float __val) { return __to_wstring(__val); }
-_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(double __val) { return __to_wstring(__val); }
-_LIBCPP_HIDE_FROM_ABI inline wstring to_wstring(long double __val) { return __to_wstring(__val); }
+inline _LIBCPP_HIDE_FROM_ABI wstring to_wstring(float __val) { return std::__to_wstring(__val); }
+inline _LIBCPP_HIDE_FROM_ABI wstring to_wstring(double __val) { return std::__to_wstring(__val); }
+inline _LIBCPP_HIDE_FROM_ABI wstring to_wstring(long double __val) { return std::__to_wstring(__val); }
 } // namespace __cpp26
 #    else
 _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val);
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 3aa9e50a7bc3d..82a316d59e55d 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1415,6 +1415,12 @@
 {'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
@@ -1636,6 +1642,7 @@
 {'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIcEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIwEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt3__112format_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112future_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'}
@@ -1769,6 +1776,7 @@
 {'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIcEE', 'size': 26, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIwEE', 'size': 26, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__112format_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112future_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'}
@@ -1906,6 +1914,7 @@
 {'is_defined': True, 'name': '_ZTVNSt3__112bad_weak_ptrE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIcEE', 'size': 104, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIwEE', 'size': 136, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__112format_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112future_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 74681c2205a34..ca339942fdeed 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1386,6 +1386,12 @@
 {'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
@@ -1607,6 +1613,7 @@
 {'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIcEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIwEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt3__112format_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112future_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'}
@@ -1740,6 +1747,7 @@
 {'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIcEE', 'size': 26, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIwEE', 'size': 26, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__112format_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112future_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'}
@@ -1877,6 +1885,7 @@
 {'is_defined': True, 'name': '_ZTVNSt3__112bad_weak_ptrE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIcEE', 'size': 104, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIwEE', 'size': 136, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__112format_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112future_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'}
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 012d65ee60187..1d579969d0014 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -389,10 +389,10 @@ string to_string(float val) { return as_string(snprintf, initial_string< string>
 string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
 string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
 
-#  if _LIBCPP_HAS_WIDE_CHARACTERS
+#if _LIBCPP_HAS_WIDE_CHARACTERS
 wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
 wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
-#  endif
+#endif
 
 _LIBCPP_END_NAMESPACE_STD

>From b379c9f5b26c32eb38b700fea216f8055f09ffa7 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 13 Mar 2025 16:41:17 +0200
Subject: [PATCH 4/6] Try to fix CI

---
 ...oid21.libcxxabi.v1.stable.exceptions.nonew.abilist | 11 ++++++++++-
 ...m-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 11 ++++++++++-
 ...m-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 11 ++++++++++-
 ...oid21.libcxxabi.v1.stable.exceptions.nonew.abilist | 11 ++++++++++-
 ...eebsd.libcxxabi.v1.stable.exceptions.nonew.abilist |  8 +++++++-
 libcxx/src/string.cpp                                 |  2 +-
 .../std/strings/string.conversions/to_string.pass.cpp |  1 +
 .../strings/string.conversions/to_wstring.pass.cpp    |  1 +
 8 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
index b38cedb012e8c..f2011af4bbf64 100644
--- a/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2329,4 +2329,13 @@
 {'is_defined': True, 'name': '__cxa_vec_dtor', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__cxa_vec_new', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__cxa_vec_new2', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__cxa_vec_new3', 'type': 'FUNC'}
\ No newline at end of file
+{'is_defined': True, 'name': '__cxa_vec_new3', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTVNSt6__ndk112format_errorE', 'size': 20, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTINSt6__ndk112format_errorE', 'size': 12, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt6__ndk112format_errorE', 'size': 26, 'type': 'OBJECT'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 9f299d65e63f8..261d75257ce80 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2017,4 +2017,13 @@
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_Znam', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnamSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_Znwm', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
\ No newline at end of file
+{'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'wEXP', 'name': '_ZTSNSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RO'}
+{'import_export': 'wEXP', 'name': '_ZTVNSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RW'}
+{'import_export': 'wEXP', 'name': '_ZTINSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RW'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEf', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEd', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEe', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 3a071b9ff52d9..aaed81659b5c1 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2017,4 +2017,13 @@
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_Znam', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnamSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'wIMP', 'is_defined': False, 'name': '_Znwm', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
\ No newline at end of file
+{'import_export': 'wIMP', 'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'wEXP', 'name': '_ZTSNSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RO'}
+{'import_export': 'wEXP', 'name': '_ZTVNSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RW'}
+{'import_export': 'wEXP', 'name': '_ZTINSt3__112format_errorE', 'is_defined': True, 'type': 'OBJECT', 'storage_mapping_class': 'RW'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEf', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEd', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2611__to_stringEe', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
+{'import_export': 'EXP', 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'is_defined': True, 'type': 'FUNC', 'storage_mapping_class': 'DS'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
index 5c8329c1f6650..6754d421e8629 100644
--- a/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2323,4 +2323,13 @@
 {'is_defined': True, 'name': '__cxa_vec_dtor', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__cxa_vec_new', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__cxa_vec_new2', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__cxa_vec_new3', 'type': 'FUNC'}
\ No newline at end of file
+{'is_defined': True, 'name': '__cxa_vec_new3', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTVNSt6__ndk112format_errorE', 'size': 40, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEg', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2611__to_stringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEg', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cpp2612__to_wstringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTINSt6__ndk112format_errorE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt6__ndk112format_errorE', 'size': 26, 'type': 'OBJECT'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index a67dc766d5e2b..49662dad5465b 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2024,4 +2024,10 @@
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
\ No newline at end of file
+{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEe', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cpp2611__to_stringEf', 'type': 'FUNC'}
\ No newline at end of file
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 1d579969d0014..3cd1dd5baed41 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -378,7 +378,7 @@ _LIBCPP_EXPORTED_FROM_ABI string __to_string(float __val) { return std::format("
 _LIBCPP_EXPORTED_FROM_ABI string __to_string(double __val) { return std::format("{}", __val); }
 _LIBCPP_EXPORTED_FROM_ABI string __to_string(long double __val) { return std::format("{}", __val); }
 
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+#if _LIBCPP_HAS_WIDE_CHARACTERS
 _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(float __val) { return std::format(L"{}", __val); }
 _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(double __val) { return std::format(L"{}", __val); }
 _LIBCPP_EXPORTED_FROM_ABI wstring __to_wstring(long double __val) { return std::format(L"{}", __val); }
diff --git a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
index 87ab89c39ffe7..6bbcba8fe1a0d 100644
--- a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
@@ -19,6 +19,7 @@
 // string to_string(long double val);
 
 #include <cassert>
+#include <clocale>
 #include <format>
 #include <string>
 #include <limits>
diff --git a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
index 6c3a5825c43aa..8473bf83c79a6 100644
--- a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
@@ -21,6 +21,7 @@
 // wstring to_wstring(long double val);
 
 #include <cassert>
+#include <clocale>
 #include <format>
 #include <string>
 #include <limits>

>From 49b255988deae2b75384470918759bd5463c816d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 14 Mar 2025 08:01:07 +0200
Subject: [PATCH 5/6] Fix FreeBSD

---
 libcxx/docs/Status/Cxx2cPapers.csv                             | 2 +-
 ...nknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 406314f493c7f..6be1148715363 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -1,7 +1,7 @@
 "Paper #","Paper Name","Meeting","Status","First released version","Notes"
 "`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18",""
 "`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
-"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","|Complete|","25",""
+"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","|Complete|","XX",""
 "`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20",""
 "`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
 "`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 49662dad5465b..ea7b6d07cdb5d 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -2025,6 +2025,9 @@
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTINSt3__112format_errorE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__112format_errorE', 'size': 23, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__112format_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEd', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEe', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17__cpp2612__to_wstringEf', 'type': 'FUNC'}

>From 3b59c593ad284e50e3b525dea02f75ea90a479c0 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 14 Mar 2025 09:25:59 +0200
Subject: [PATCH 6/6] Fix Build and Test libc++ / stage3
 (generic-no-exceptions, libcxx-self-hosted-linux)

---
 ...wn-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index ca339942fdeed..ff2e79f51d3ad 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1613,7 +1613,6 @@
 {'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIcEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIwEE', 'size': 24, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTINSt3__112format_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112future_errorE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'}
@@ -1747,7 +1746,6 @@
 {'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIcEE', 'size': 26, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIwEE', 'size': 26, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTSNSt3__112format_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112future_errorE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'}
@@ -1885,7 +1883,6 @@
 {'is_defined': True, 'name': '_ZTVNSt3__112bad_weak_ptrE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIcEE', 'size': 104, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIwEE', 'size': 136, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTVNSt3__112format_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112future_errorE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'}



More information about the libcxx-commits mailing list