[libcxx-commits] [libcxx] [libc++] P3391R2: `constexpr` integral overloads of `to_(w)string` (PR #205025)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jun 23 01:24:38 PDT 2026
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/205025
>From fda1aaf3bf91965678b844e5c8e736a2cec12df0 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 22 Jun 2026 11:17:25 +0800
Subject: [PATCH 1/6] [libc++] P3391R2: `constexpr` integral overloads of
`to_(w)string`
Also implements related LWG4531.
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/docs/Status/Cxx26Papers.csv | 2 +-
libcxx/docs/Status/Cxx29Issues.csv | 2 +-
libcxx/include/string | 55 +++++++++++
libcxx/include/version | 5 +-
libcxx/src/string.cpp | 50 +++++-----
.../test/libcxx/transitive_includes/cxx26.csv | 7 ++
.../string.version.compile.pass.cpp | 4 +-
.../version.version.compile.pass.cpp | 4 +-
.../string.conversions/to_string.pass.cpp | 15 ++-
.../string.conversions/to_wstring.pass.cpp | 15 ++-
libcxx/test/support/parse_integer.h | 96 +++++++++++++++----
.../generate_feature_test_macro_components.py | 2 +-
13 files changed, 201 insertions(+), 58 deletions(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 8e26bdcd860c1..3baa0acb5c06a 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -450,6 +450,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_constexpr_queue`` ``202502L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_constexpr_string`` ``202511L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_constrained_equality`` ``202411L``
---------------------------------------------------------- -----------------
``__cpp_lib_copyable_function`` *unimplemented*
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index a951ac4c6c833..8dce1ed74811a 100644
--- a/libcxx/docs/Status/Cxx26Papers.csv
+++ b/libcxx/docs/Status/Cxx26Papers.csv
@@ -175,7 +175,7 @@
"`P3887R1 <https://wg21.link/P3887R1>`__","Make ``when_all`` a Ronseal Algorithm","2025-11 (Kona)","","","`#171289 <https://github.com/llvm/llvm-project/issues/171289>`__",""
"`P3923R0 <https://wg21.link/P3923R0>`__","Additional NB comment resolutions for Kona 2025","2025-11 (Kona)","","","`#171290 <https://github.com/llvm/llvm-project/issues/171290>`__",""
"`P3371R5 <https://wg21.link/P3371R5>`__","Fix C++26 by making the rank-1, rank-2, rank-k, and rank-2k updates consistent with the BLAS","2025-11 (Kona)","","","`#171291 <https://github.com/llvm/llvm-project/issues/171291>`__",""
-"`P3391R2 <https://wg21.link/P3391R2>`__","``constexpr`` ``std::format``","2025-11 (Kona)","","","`#171292 <https://github.com/llvm/llvm-project/issues/171292>`__",""
+"`P3391R2 <https://wg21.link/P3391R2>`__","``constexpr`` ``std::format``","2025-11 (Kona)","|Partial|","","`#171292 <https://github.com/llvm/llvm-project/issues/171292>`__","``std::to_(w)string`` parts are implemented in LLVM 23."
"`P3913R1 <https://wg21.link/P3913R1>`__","Optimize ``for std::optional`` in range adaptors","2025-11 (Kona)","","","`#171294 <https://github.com/llvm/llvm-project/issues/171294>`__",""
"","","","","","",""
"`P3726R2 <https://wg21.link/P3726R2>`__","Adjustments to Union Lifetime Rules","2026-03 (Croydon)","","","`#189560 <https://github.com/llvm/llvm-project/issues/189560>`__",""
diff --git a/libcxx/docs/Status/Cxx29Issues.csv b/libcxx/docs/Status/Cxx29Issues.csv
index d9e245a9a11c0..072ab8effa121 100644
--- a/libcxx/docs/Status/Cxx29Issues.csv
+++ b/libcxx/docs/Status/Cxx29Issues.csv
@@ -13,7 +13,7 @@
"`LWG4487 <https://wg21.link/LWG4487>`__","Is member ``is_steady`` of a *Cpp17Clock* type required to be usable in constant expressions?","2026-06 (Brno)","","","`#204451 <https://github.com/llvm/llvm-project/issues/204451>`__",""
"`LWG4490 <https://wg21.link/LWG4490>`__","Allow calling ``std::ranges::size`` in ranges algorithms","2026-06 (Brno)","","","`#204452 <https://github.com/llvm/llvm-project/issues/204452>`__",""
"`LWG4521 <https://wg21.link/LWG4521>`__","Improve [atomics.order] p10 to have a consistent way with [intro.races]","2026-06 (Brno)","","","`#204453 <https://github.com/llvm/llvm-project/issues/204453>`__",""
-"`LWG4531 <https://wg21.link/LWG4531>`__","Should there be a feature-test macro update for ``constexpr`` ``std::to_(w)string``?","2026-06 (Brno)","","","`#204454 <https://github.com/llvm/llvm-project/issues/204454>`__",""
+"`LWG4531 <https://wg21.link/LWG4531>`__","Should there be a feature-test macro update for ``constexpr`` ``std::to_(w)string``?","2026-06 (Brno)","|Complete|","23","`#204454 <https://github.com/llvm/llvm-project/issues/204454>`__",""
"`LWG4567 <https://wg21.link/LWG4567>`__","Feature test macro value for ``apply_result``, ``is_applicable``","2026-06 (Brno)","","","`#204455 <https://github.com/llvm/llvm-project/issues/204455>`__",""
"`LWG4568 <https://wg21.link/LWG4568>`__","``std::execution::spawn_future`` is mishandling dependent senders","2026-06 (Brno)","","","`#204456 <https://github.com/llvm/llvm-project/issues/204456>`__",""
"`LWG4579 <https://wg21.link/LWG4579>`__","``make-state<Rcvr>::state-type::complete`` uses ``Env`` which is not in scope","2026-06 (Brno)","","","`#204457 <https://github.com/llvm/llvm-project/issues/204457>`__",""
diff --git a/libcxx/include/string b/libcxx/include/string
index e5bc854cd34f3..d1217b65475bd 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -663,6 +663,12 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
# include <cwchar>
# endif
+# if _LIBCPP_STD_VER >= 26
+# include <__charconv/to_chars_integral.h>
+# include <__charconv/to_chars_result.h>
+# include <__system_error/errc.h>
+# endif
+
// standard-mandated includes
// [iterator.range]
@@ -3774,12 +3780,41 @@ stoull(const string& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr);
+# if _LIBCPP_STD_VER >= 26
+
+template <class _String, class _Integer>
+constexpr _String __integer_to_string(_Integer __val) {
+ // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
+ // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), so we need +1 here.
+ constexpr size_t __buf_size = numeric_limits<_Integer>::digits10 + 2; // +1 for minus, +1 for digits10
+ char __buf[__buf_size];
+ const auto [__ptr, __ec] = std::to_chars(__buf, __buf + __buf_size, __val);
+ _LIBCPP_ASSERT_INTERNAL(__ec == errc(), "__buf_size must be large enough to accommodate the value");
+ return _String(__buf, __ptr);
+}
+
+inline namespace __cpp26 {
+
+[[nodiscard]] constexpr string to_string(int __val) { return std::__integer_to_string<string>(__val); }
+[[nodiscard]] constexpr string to_string(unsigned __val) { return std::__integer_to_string<string>(__val); }
+[[nodiscard]] constexpr string to_string(long __val) { return std::__integer_to_string<string>(__val); }
+[[nodiscard]] constexpr string to_string(unsigned long __val) { return std::__integer_to_string<string>(__val); }
+[[nodiscard]] constexpr string to_string(long long __val) { return std::__integer_to_string<string>(__val); }
+[[nodiscard]] constexpr string to_string(unsigned long long __val) { return std::__integer_to_string<string>(__val); }
+
+} // namespace __cpp26
+
+# else // _LIBCPP_STD_VER >= 26
+
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val);
+
+# endif // _LIBCPP_STD_VER >= 26
+
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val);
@@ -3798,12 +3833,32 @@ stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr);
+# if _LIBCPP_STD_VER >= 26
+
+inline namespace __cpp26 {
+
+[[nodiscard]] constexpr wstring to_wstring(int __val) { return std::__integer_to_string<wstring>(__val); }
+[[nodiscard]] constexpr wstring to_wstring(unsigned __val) { return std::__integer_to_string<wstring>(__val); }
+[[nodiscard]] constexpr wstring to_wstring(long __val) { return std::__integer_to_string<wstring>(__val); }
+[[nodiscard]] constexpr wstring to_wstring(unsigned long __val) { return std::__integer_to_string<wstring>(__val); }
+[[nodiscard]] constexpr wstring to_wstring(long long __val) { return std::__integer_to_string<wstring>(__val); }
+[[nodiscard]] constexpr wstring to_wstring(unsigned long long __val) {
+ return std::__integer_to_string<wstring>(__val);
+}
+
+} // namespace __cpp26
+
+# else // _LIBCPP_STD_VER >= 26
+
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val);
+
+# endif // _LIBCPP_STD_VER >= 26
+
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val);
diff --git a/libcxx/include/version b/libcxx/include/version
index 7f2dc9e4b72ab..ed278dff0f59f 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -84,7 +84,8 @@ __cpp_lib_constexpr_memory 202202L <memory>
__cpp_lib_constexpr_new 202406L <new>
__cpp_lib_constexpr_numeric 201911L <numeric>
__cpp_lib_constexpr_queue 202502L <queue>
-__cpp_lib_constexpr_string 201907L <string>
+__cpp_lib_constexpr_string 202511L <string>
+ 201907L // C++20
__cpp_lib_constexpr_string_view 201811L <string_view>
__cpp_lib_constexpr_tuple 201811L <tuple>
__cpp_lib_constexpr_typeinfo 202106L <typeinfo>
@@ -575,6 +576,8 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_constexpr_new 202406L
# endif
# define __cpp_lib_constexpr_queue 202502L
+# undef __cpp_lib_constexpr_string
+# define __cpp_lib_constexpr_string 202511L
# define __cpp_lib_constrained_equality 202411L
// # define __cpp_lib_copyable_function 202306L
// # define __cpp_lib_debugging 202311L
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index b55f9ff5c9a43..71a0689eecc17 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -328,34 +328,36 @@ inline wide_printf get_swprintf() {
}
#endif // _LIBCPP_HAS_WIDE_CHARACTERS
-template <typename S, typename V>
-S i_to_string(V v) {
- // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
- // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
- // so we need +1 here.
- constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10
- char buf[bufsize];
- const auto res = to_chars(buf, buf + bufsize, v);
- _LIBCPP_ASSERT_INTERNAL(res.ec == errc(), "bufsize must be large enough to accomodate the value");
- return S(buf, res.ptr);
-}
-
} // unnamed namespace
-string to_string(int val) { return i_to_string< string>(val); }
-string to_string(long val) { return i_to_string< string>(val); }
-string to_string(long long val) { return i_to_string< string>(val); }
-string to_string(unsigned val) { return i_to_string< string>(val); }
-string to_string(unsigned long val) { return i_to_string< string>(val); }
-string to_string(unsigned long long val) { return i_to_string< string>(val); }
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long);
+
+string to_string(int val) { return __cpp26::to_string(val); }
+string to_string(long val) { return __cpp26::to_string(val); }
+string to_string(long long val) { return __cpp26::to_string(val); }
+string to_string(unsigned val) { return __cpp26::to_string(val); }
+string to_string(unsigned long val) { return __cpp26::to_string(val); }
+string to_string(unsigned long long val) { return __cpp26::to_string(val); }
#if _LIBCPP_HAS_WIDE_CHARACTERS
-wstring to_wstring(int val) { return i_to_string<wstring>(val); }
-wstring to_wstring(long val) { return i_to_string<wstring>(val); }
-wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
-wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
-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); }
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long);
+
+wstring to_wstring(int val) { return __cpp26::to_wstring(val); }
+wstring to_wstring(long val) { return __cpp26::to_wstring(val); }
+wstring to_wstring(long long val) { return __cpp26::to_wstring(val); }
+wstring to_wstring(unsigned val) { return __cpp26::to_wstring(val); }
+wstring to_wstring(unsigned long val) { return __cpp26::to_wstring(val); }
+wstring to_wstring(unsigned long long val) { return __cpp26::to_wstring(val); }
#endif
string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 1450a13e125ef..df9510c63b8d4 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -45,6 +45,7 @@ bit cstdint
bit limits
bit version
bitset cctype
+bitset cerrno
bitset climits
bitset compare
bitset cstdint
@@ -130,6 +131,7 @@ cinttypes cstdint
cmath limits
cmath version
codecvt cctype
+codecvt cerrno
codecvt climits
codecvt clocale
codecvt compare
@@ -719,6 +721,7 @@ print tuple
print typeinfo
print version
queue cctype
+queue cerrno
queue climits
queue compare
queue cstdint
@@ -737,6 +740,7 @@ queue tuple
queue vector
queue version
random cctype
+random cerrno
random climits
random cmath
random compare
@@ -780,6 +784,7 @@ ratio climits
ratio cstdint
ratio version
regex cctype
+regex cerrno
regex climits
regex clocale
regex compare
@@ -905,6 +910,7 @@ streambuf tuple
streambuf typeinfo
streambuf version
string cctype
+string cerrno
string climits
string compare
string cstdint
@@ -1083,6 +1089,7 @@ variant initializer_list
variant limits
variant version
vector cctype
+vector cerrno
vector climits
vector compare
vector cstdint
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 147854eead2cc..324dc4dbe3200 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
@@ -417,8 +417,8 @@
# ifndef __cpp_lib_constexpr_string
# error "__cpp_lib_constexpr_string should be defined in c++26"
# endif
-# if __cpp_lib_constexpr_string != 201907L
-# error "__cpp_lib_constexpr_string should have the value 201907L in c++26"
+# if __cpp_lib_constexpr_string != 202511L
+# error "__cpp_lib_constexpr_string should have the value 202511L in c++26"
# endif
# ifndef __cpp_lib_containers_ranges
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 d9c78b73f7e23..aed1162977efc 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
@@ -6747,8 +6747,8 @@
# ifndef __cpp_lib_constexpr_string
# error "__cpp_lib_constexpr_string should be defined in c++26"
# endif
-# if __cpp_lib_constexpr_string != 201907L
-# error "__cpp_lib_constexpr_string should have the value 201907L in c++26"
+# if __cpp_lib_constexpr_string != 202511L
+# error "__cpp_lib_constexpr_string should have the value 202511L in c++26"
# endif
# ifndef __cpp_lib_constexpr_string_view
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..a36d21592b08d 100644
--- a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
@@ -26,7 +26,7 @@
#include "test_macros.h"
template <class T>
-void test_signed() {
+TEST_CONSTEXPR_CXX26 void test_signed() {
{
std::string s = std::to_string(T(0));
assert(s.size() == 1);
@@ -59,7 +59,7 @@ void test_signed() {
}
template <class T>
-void test_unsigned() {
+TEST_CONSTEXPR_CXX26 void test_unsigned() {
{
std::string s = std::to_string(T(0));
assert(s.size() == 1);
@@ -102,16 +102,25 @@ void test_float() {
}
}
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test_integers() {
test_signed<int>();
test_signed<long>();
test_signed<long long>();
test_unsigned<unsigned>();
test_unsigned<unsigned long>();
test_unsigned<unsigned long long>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test_integers();
test_float<float>();
test_float<double>();
test_float<long double>();
+#if TEST_STD_VER >= 26
+ static_assert(test_integers());
+#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..22d06bffb84b8 100644
--- a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
@@ -28,7 +28,7 @@
#include "test_macros.h"
template <class T>
-void test_signed() {
+TEST_CONSTEXPR_CXX26 void test_signed() {
{
std::wstring s = std::to_wstring(T(0));
assert(s.size() == 1);
@@ -61,7 +61,7 @@ void test_signed() {
}
template <class T>
-void test_unsigned() {
+TEST_CONSTEXPR_CXX26 void test_unsigned() {
{
std::wstring s = std::to_wstring(T(0));
assert(s.size() == 1);
@@ -104,16 +104,25 @@ void test_float() {
}
}
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test_integers() {
test_signed<int>();
test_signed<long>();
test_signed<long long>();
test_unsigned<unsigned>();
test_unsigned<unsigned long>();
test_unsigned<unsigned long long>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test_integers();
test_float<float>();
test_float<double>();
test_float<long double>();
+#if TEST_STD_VER >= 26
+ static_assert(test_integers());
+#endif
return 0;
}
diff --git a/libcxx/test/support/parse_integer.h b/libcxx/test/support/parse_integer.h
index 36f8f7b79881b..d6144b17f57c5 100644
--- a/libcxx/test/support/parse_integer.h
+++ b/libcxx/test/support/parse_integer.h
@@ -9,64 +9,120 @@
#ifndef LIBCPP_TEST_SUPPORT_PARSE_INTEGER_H
#define LIBCPP_TEST_SUPPORT_PARSE_INTEGER_H
+#include <charconv>
+#include <cstdlib>
#include <string>
+#include <system_error>
+#include <type_traits>
+
+#include "test_macros.h"
namespace detail {
template <class T>
struct parse_integer_impl;
+#if TEST_STD_VER >= 23
+template <class I, class CharT>
+consteval I consteval_parse_integer(const std::basic_string<CharT>& str) {
+ I n;
+ auto [ptr, ec] = [&n, &str] {
+ if constexpr (std::is_same_v<CharT, char>) {
+ return std::from_chars(str.data(), str.data() + str.size(), n);
+ } else {
+ std::string s;
+ for (auto c : str)
+ s.push_back(static_cast<char>(c));
+ return std::from_chars(s.data(), s.data() + s.size(), n);
+ }
+ }();
+ if (ec != std::errc{})
+ std::abort();
+ return n;
+}
+#endif
+
template <>
struct parse_integer_impl<int> {
- template <class CharT>
- int operator()(std::basic_string<CharT> const& str) const {
- return std::stoi(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 int operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<int>(str);
}
+#endif
+ return std::stoi(str);
+ }
};
template <>
struct parse_integer_impl<long> {
- template <class CharT>
- long operator()(std::basic_string<CharT> const& str) const {
- return std::stol(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 long operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<long>(str);
}
+#endif
+ return std::stol(str);
+ }
};
template <>
struct parse_integer_impl<long long> {
- template <class CharT>
- long long operator()(std::basic_string<CharT> const& str) const {
- return std::stoll(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 long long operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<long long>(str);
}
+#endif
+ return std::stoll(str);
+ }
};
template <>
struct parse_integer_impl<unsigned int> {
- template <class CharT>
- unsigned int operator()(std::basic_string<CharT> const& str) const {
- return std::stoul(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 unsigned int operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<unsigned int>(str);
}
+#endif
+ return std::stoul(str);
+ }
};
template <>
struct parse_integer_impl<unsigned long> {
- template <class CharT>
- unsigned long operator()(std::basic_string<CharT> const& str) const {
- return std::stoul(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 unsigned long operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<unsigned long>(str);
}
+#endif
+ return std::stoul(str);
+ }
};
template <>
struct parse_integer_impl<unsigned long long> {
- template <class CharT>
- unsigned long long operator()(std::basic_string<CharT> const& str) const {
- return std::stoull(str);
+ template <class CharT>
+ TEST_CONSTEXPR_CXX23 unsigned long long operator()(std::basic_string<CharT> const& str) const {
+#if TEST_STD_VER >= 23
+ if consteval {
+ return consteval_parse_integer<unsigned long long>(str);
}
+#endif
+ return std::stoull(str);
+ }
};
} // namespace detail
template <class T, class CharT>
-T parse_integer(std::basic_string<CharT> const& str) {
- return detail::parse_integer_impl<T>()(str);
+TEST_CONSTEXPR_CXX23 T parse_integer(std::basic_string<CharT> const& str) {
+ return detail::parse_integer_impl<T>()(str);
}
#endif // LIBCPP_TEST_SUPPORT_PARSE_INTEGER_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index d764a1f677ba6..1f4961fda4d6f 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -434,7 +434,7 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_constexpr_string",
- "values": {"c++20": 201907},
+ "values": {"c++20": 201907, "c++26": 202511},
"headers": ["string"],
},
{
>From 4baebb05bb50957edce254c8d93947a07876644f Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Jun 2026 09:41:44 +0800
Subject: [PATCH 2/6] Use `_LIBCPP_PREFERRED_OVERLOAD` as suggested
---
libcxx/include/string | 154 +++++++++++++++++++++++++++++-------------
libcxx/src/string.cpp | 32 +++++----
2 files changed, 125 insertions(+), 61 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index d1217b65475bd..72ff5fe70d971 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3780,40 +3780,14 @@ stoull(const string& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr);
-# if _LIBCPP_STD_VER >= 26
-
-template <class _String, class _Integer>
-constexpr _String __integer_to_string(_Integer __val) {
- // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
- // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), so we need +1 here.
- constexpr size_t __buf_size = numeric_limits<_Integer>::digits10 + 2; // +1 for minus, +1 for digits10
- char __buf[__buf_size];
- const auto [__ptr, __ec] = std::to_chars(__buf, __buf + __buf_size, __val);
- _LIBCPP_ASSERT_INTERNAL(__ec == errc(), "__buf_size must be large enough to accommodate the value");
- return _String(__buf, __ptr);
-}
-
-inline namespace __cpp26 {
-
-[[nodiscard]] constexpr string to_string(int __val) { return std::__integer_to_string<string>(__val); }
-[[nodiscard]] constexpr string to_string(unsigned __val) { return std::__integer_to_string<string>(__val); }
-[[nodiscard]] constexpr string to_string(long __val) { return std::__integer_to_string<string>(__val); }
-[[nodiscard]] constexpr string to_string(unsigned long __val) { return std::__integer_to_string<string>(__val); }
-[[nodiscard]] constexpr string to_string(long long __val) { return std::__integer_to_string<string>(__val); }
-[[nodiscard]] constexpr string to_string(unsigned long long __val) { return std::__integer_to_string<string>(__val); }
-
-} // namespace __cpp26
-
-# else // _LIBCPP_STD_VER >= 26
-
+# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val);
-
-# endif // _LIBCPP_STD_VER >= 26
+# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val);
@@ -3833,37 +3807,123 @@ stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr);
-# if _LIBCPP_STD_VER >= 26
-
-inline namespace __cpp26 {
-
-[[nodiscard]] constexpr wstring to_wstring(int __val) { return std::__integer_to_string<wstring>(__val); }
-[[nodiscard]] constexpr wstring to_wstring(unsigned __val) { return std::__integer_to_string<wstring>(__val); }
-[[nodiscard]] constexpr wstring to_wstring(long __val) { return std::__integer_to_string<wstring>(__val); }
-[[nodiscard]] constexpr wstring to_wstring(unsigned long __val) { return std::__integer_to_string<wstring>(__val); }
-[[nodiscard]] constexpr wstring to_wstring(long long __val) { return std::__integer_to_string<wstring>(__val); }
-[[nodiscard]] constexpr wstring to_wstring(unsigned long long __val) {
- return std::__integer_to_string<wstring>(__val);
-}
-
-} // namespace __cpp26
-
-# else // _LIBCPP_STD_VER >= 26
-
+# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val);
-
-# endif // _LIBCPP_STD_VER >= 26
+# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val);
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+# if _LIBCPP_STD_VER >= 26
+
+// Note: _LIBCPP_ALWAYS_INLINE is used for generating direct invocations to dylib versions for Clang,
+// which avoids code size regression in C++26.
+
+template <class _String, class _Integer>
+constexpr _String __integer_to_string(_Integer __val) {
+ // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
+ // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), so we need +1 here.
+ constexpr size_t __buf_size = numeric_limits<_Integer>::digits10 + 2; // +1 for minus, +1 for digits10
+ char __buf[__buf_size];
+ const auto [__ptr, __ec] = std::to_chars(__buf, __buf + __buf_size, __val);
+ _LIBCPP_ASSERT_INTERNAL(__ec == errc(), "__buf_size must be large enough to accommodate the value");
+ return _String(__buf, __ptr);
+}
+
+template <class _Integer>
+_LIBCPP_ALWAYS_INLINE constexpr string __to_string(_Integer __val) {
+# if _LIBCPP_PREFERRED_OVERLOAD
+ if !consteval {
+ return std::to_string(__val);
+ } else
+# endif // _LIBCPP_PREFERRED_OVERLOAD
+ {
+ return std::__integer_to_string<string>(__val);
+ }
+}
+
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+template <class _Integer>
+_LIBCPP_ALWAYS_INLINE constexpr wstring __to_wstring(_Integer __val) {
+# if _LIBCPP_PREFERRED_OVERLOAD
+ if !consteval {
+ return std::to_wstring(__val);
+ } else
+# endif // _LIBCPP_PREFERRED_OVERLOAD
+ {
+ return std::__integer_to_string<wstring>(__val);
+ }
+}
+# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+
+inline namespace __cpp26 {
+
+# ifdef _LIBCPP_PREFERRED_OVERLOAD
+# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE _LIBCPP_PREFERRED_OVERLOAD
+# else // _LIBCPP_PREFERRED_OVERLOAD
+# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
+# endif // _LIBCPP_PREFERRED_OVERLOAD
+
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(int __val) {
+ return std::__to_string(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(unsigned __val) {
+ return std::__to_string(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(long __val) {
+ return std::__to_string(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+to_string(unsigned long __val) {
+ return std::__to_string(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+to_string(long long __val) {
+ return std::__to_string(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+to_string(unsigned long long __val) {
+ return std::__to_string(__val);
+}
+
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(int __val) {
+ return std::__to_wstring(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+to_wstring(unsigned __val) {
+ return std::__to_wstring(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(long __val) {
+ return std::__to_wstring(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+to_wstring(unsigned long __val) {
+ return std::__to_wstring(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+to_wstring(long long __val) {
+ return std::__to_wstring(__val);
+}
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+to_wstring(unsigned long long __val) {
+ return std::__to_wstring(__val);
+}
+# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+
+# undef _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
+
+} // namespace __cpp26
+
+# endif // _LIBCPP_STD_VER >= 26
+
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_TEMPLATE_DATA_VIS const typename basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::npos;
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 71a0689eecc17..812c4080650f0 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -330,6 +330,7 @@ inline wide_printf get_swprintf() {
} // unnamed namespace
+#ifndef _LIBCPP_PREFERRED_OVERLOAD
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long);
@@ -337,27 +338,30 @@ inline wide_printf get_swprintf() {
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long);
-string to_string(int val) { return __cpp26::to_string(val); }
-string to_string(long val) { return __cpp26::to_string(val); }
-string to_string(long long val) { return __cpp26::to_string(val); }
-string to_string(unsigned val) { return __cpp26::to_string(val); }
-string to_string(unsigned long val) { return __cpp26::to_string(val); }
-string to_string(unsigned long long val) { return __cpp26::to_string(val); }
-
-#if _LIBCPP_HAS_WIDE_CHARACTERS
+# if _LIBCPP_HAS_WIDE_CHARACTERS
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long);
+# endif
+#endif
+
+string to_string(int val) { return std::__integer_to_string<string>(val); }
+string to_string(long val) { return std::__integer_to_string<string>(val); }
+string to_string(long long val) { return std::__integer_to_string<string>(val); }
+string to_string(unsigned val) { return std::__integer_to_string<string>(val); }
+string to_string(unsigned long val) { return std::__integer_to_string<string>(val); }
+string to_string(unsigned long long val) { return std::__integer_to_string<string>(val); }
-wstring to_wstring(int val) { return __cpp26::to_wstring(val); }
-wstring to_wstring(long val) { return __cpp26::to_wstring(val); }
-wstring to_wstring(long long val) { return __cpp26::to_wstring(val); }
-wstring to_wstring(unsigned val) { return __cpp26::to_wstring(val); }
-wstring to_wstring(unsigned long val) { return __cpp26::to_wstring(val); }
-wstring to_wstring(unsigned long long val) { return __cpp26::to_wstring(val); }
+#if _LIBCPP_HAS_WIDE_CHARACTERS
+wstring to_wstring(int val) { return std::__integer_to_string<wstring>(val); }
+wstring to_wstring(long val) { return std::__integer_to_string<wstring>(val); }
+wstring to_wstring(long long val) { return std::__integer_to_string<wstring>(val); }
+wstring to_wstring(unsigned val) { return std::__integer_to_string<wstring>(val); }
+wstring to_wstring(unsigned long val) { return std::__integer_to_string<wstring>(val); }
+wstring to_wstring(unsigned long long val) { return std::__integer_to_string<wstring>(val); }
#endif
string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
>From 2da099bade0b095a8ced5dc4e20452e46e41e44f Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Jun 2026 09:45:01 +0800
Subject: [PATCH 3/6] Fixup `#ifdef _LIBCPP_PREFERRED_OVERLOAD`
---
libcxx/include/string | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index 72ff5fe70d971..61e347c34075c 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3839,7 +3839,7 @@ constexpr _String __integer_to_string(_Integer __val) {
template <class _Integer>
_LIBCPP_ALWAYS_INLINE constexpr string __to_string(_Integer __val) {
-# if _LIBCPP_PREFERRED_OVERLOAD
+# ifdef _LIBCPP_PREFERRED_OVERLOAD
if !consteval {
return std::to_string(__val);
} else
@@ -3852,7 +3852,7 @@ _LIBCPP_ALWAYS_INLINE constexpr string __to_string(_Integer __val) {
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class _Integer>
_LIBCPP_ALWAYS_INLINE constexpr wstring __to_wstring(_Integer __val) {
-# if _LIBCPP_PREFERRED_OVERLOAD
+# ifdef _LIBCPP_PREFERRED_OVERLOAD
if !consteval {
return std::to_wstring(__val);
} else
>From 0cfcfd7cbe702bba0c048928a52c8c370b9f0187 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Jun 2026 16:16:25 +0800
Subject: [PATCH 4/6] Address review comments
---
libcxx/include/string | 108 +++++++-----------
libcxx/src/string.cpp | 18 ---
.../test/libcxx/transitive_includes/cxx03.csv | 2 +
.../test/libcxx/transitive_includes/cxx11.csv | 2 +
.../test/libcxx/transitive_includes/cxx14.csv | 2 +
.../test/libcxx/transitive_includes/cxx17.csv | 2 +
.../test/libcxx/transitive_includes/cxx20.csv | 2 +
.../test/libcxx/transitive_includes/cxx23.csv | 4 +
8 files changed, 58 insertions(+), 82 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index 61e347c34075c..b5b74aecfb317 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -596,6 +596,8 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
# include <__algorithm/remove.h>
# include <__algorithm/remove_if.h>
# include <__assert>
+# include <__charconv/to_chars_integral.h>
+# include <__charconv/to_chars_result.h>
# include <__config>
# include <__cstddef/size_t.h>
# include <__debug_utils/sanitizers.h>
@@ -625,6 +627,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
# include <__ranges/from_range.h>
# include <__string/char_traits.h>
# include <__string/extern_template_lists.h>
+# include <__system_error/errc.h>
# include <__type_traits/conditional.h>
# include <__type_traits/desugars_to.h>
# include <__type_traits/enable_if.h>
@@ -663,12 +666,6 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
# include <cwchar>
# endif
-# if _LIBCPP_STD_VER >= 26
-# include <__charconv/to_chars_integral.h>
-# include <__charconv/to_chars_result.h>
-# include <__system_error/errc.h>
-# endif
-
// standard-mandated includes
// [iterator.range]
@@ -3780,14 +3777,14 @@ stoull(const string& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr);
-# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
+# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD) || defined(_LIBCPP_BUILDING_LIBRARY)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val);
-# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
+# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD) || defined(_LIBCPP_BUILDING_LIBRARY)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val);
@@ -3807,14 +3804,14 @@ stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr);
-# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
+# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD) || defined(_LIBCPP_BUILDING_LIBRARY)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val);
-# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD)
+# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_PREFERRED_OVERLOAD) || defined(_LIBCPP_BUILDING_LIBRARY)
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val);
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val);
@@ -3823,11 +3820,8 @@ stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10);
# if _LIBCPP_STD_VER >= 26
-// Note: _LIBCPP_ALWAYS_INLINE is used for generating direct invocations to dylib versions for Clang,
-// which avoids code size regression in C++26.
-
template <class _String, class _Integer>
-constexpr _String __integer_to_string(_Integer __val) {
+_LIBCPP_HIDE_FROM_ABI constexpr _String __integer_to_string(_Integer __val) {
// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), so we need +1 here.
constexpr size_t __buf_size = numeric_limits<_Integer>::digits10 + 2; // +1 for minus, +1 for digits10
@@ -3837,90 +3831,76 @@ constexpr _String __integer_to_string(_Integer __val) {
return _String(__buf, __ptr);
}
-template <class _Integer>
-_LIBCPP_ALWAYS_INLINE constexpr string __to_string(_Integer __val) {
+template <class _CharT, class _Integer>
+_LIBCPP_HIDE_FROM_ABI constexpr string __to_basic_string(_Integer __val) {
# ifdef _LIBCPP_PREFERRED_OVERLOAD
if !consteval {
return std::to_string(__val);
} else
# endif // _LIBCPP_PREFERRED_OVERLOAD
{
- return std::__integer_to_string<string>(__val);
+ return std::__integer_to_string<basic_string<_CharT>>(__val);
}
}
-# if _LIBCPP_HAS_WIDE_CHARACTERS
-template <class _Integer>
-_LIBCPP_ALWAYS_INLINE constexpr wstring __to_wstring(_Integer __val) {
+# if !defined(_LIBCPP_BUILDING_LIBRARY)
+
# ifdef _LIBCPP_PREFERRED_OVERLOAD
- if !consteval {
- return std::to_wstring(__val);
- } else
+# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE _LIBCPP_PREFERRED_OVERLOAD
+# else // _LIBCPP_PREFERRED_OVERLOAD
+# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
# endif // _LIBCPP_PREFERRED_OVERLOAD
- {
- return std::__integer_to_string<wstring>(__val);
- }
-}
-# endif // _LIBCPP_HAS_WIDE_CHARACTERS
-
-inline namespace __cpp26 {
-
-# ifdef _LIBCPP_PREFERRED_OVERLOAD
-# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE _LIBCPP_PREFERRED_OVERLOAD
-# else // _LIBCPP_PREFERRED_OVERLOAD
-# define _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
-# endif // _LIBCPP_PREFERRED_OVERLOAD
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(int __val) {
- return std::__to_string(__val);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(int __val) {
+ return std::__to_basic_string<char>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(unsigned __val) {
- return std::__to_string(__val);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(unsigned __val) {
+ return std::__to_basic_string<char>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(long __val) {
- return std::__to_string(__val);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string to_string(long __val) {
+ return std::__to_basic_string<char>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
to_string(unsigned long __val) {
- return std::__to_string(__val);
+ return std::__to_basic_string<char>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
to_string(long long __val) {
- return std::__to_string(__val);
+ return std::__to_basic_string<char>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr string
to_string(unsigned long long __val) {
- return std::__to_string(__val);
+ return std::__to_basic_string<char>(__val);
}
-# if _LIBCPP_HAS_WIDE_CHARACTERS
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(int __val) {
- return std::__to_wstring(__val);
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(int __val) {
+ return std::__to_basic_string<wchar_t>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
to_wstring(unsigned __val) {
- return std::__to_wstring(__val);
+ return std::__to_basic_string<wchar_t>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(long __val) {
- return std::__to_wstring(__val);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring to_wstring(long __val) {
+ return std::__to_basic_string<wchar_t>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
to_wstring(unsigned long __val) {
- return std::__to_wstring(__val);
+ return std::__to_basic_string<wchar_t>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
to_wstring(long long __val) {
- return std::__to_wstring(__val);
+ return std::__to_basic_string<wchar_t>(__val);
}
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE constexpr wstring
to_wstring(unsigned long long __val) {
- return std::__to_wstring(__val);
+ return std::__to_basic_string<wchar_t>(__val);
}
-# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+# endif // _LIBCPP_HAS_WIDE_CHARACTERS
-# undef _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
+# undef _LIBCPP_PREFERRED_OVERLOAD_IF_AVAILABLE
-} // namespace __cpp26
+# endif // !defined(_LIBCPP_BUILDING_LIBRARY)
# endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 812c4080650f0..fcbd1f2800073 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -330,24 +330,6 @@ inline wide_printf get_swprintf() {
} // unnamed namespace
-#ifndef _LIBCPP_PREFERRED_OVERLOAD
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long);
-
-# if _LIBCPP_HAS_WIDE_CHARACTERS
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long);
-[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long);
-# endif
-#endif
-
string to_string(int val) { return std::__integer_to_string<string>(val); }
string to_string(long val) { return std::__integer_to_string<string>(val); }
string to_string(long long val) { return std::__integer_to_string<string>(val); }
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index c0031543e47bc..6098fea245611 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -156,6 +156,7 @@ bitset algorithm
bitset atomic
bitset bit
bitset cctype
+bitset cerrno
bitset climits
bitset cmath
bitset compare
@@ -2077,6 +2078,7 @@ string algorithm
string atomic
string bit
string cctype
+string cerrno
string climits
string cmath
string compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index c0031543e47bc..6098fea245611 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -156,6 +156,7 @@ bitset algorithm
bitset atomic
bitset bit
bitset cctype
+bitset cerrno
bitset climits
bitset cmath
bitset compare
@@ -2077,6 +2078,7 @@ string algorithm
string atomic
string bit
string cctype
+string cerrno
string climits
string cmath
string compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index c2eb5b44e8d7a..690a39e09c110 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -159,6 +159,7 @@ bitset algorithm
bitset atomic
bitset bit
bitset cctype
+bitset cerrno
bitset climits
bitset cmath
bitset compare
@@ -2118,6 +2119,7 @@ string algorithm
string atomic
string bit
string cctype
+string cerrno
string climits
string cmath
string compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 332cb62f35b5f..a50204ecb4b9a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -156,6 +156,7 @@ bitset algorithm
bitset atomic
bitset bit
bitset cctype
+bitset cerrno
bitset climits
bitset cmath
bitset compare
@@ -2130,6 +2131,7 @@ string algorithm
string atomic
string bit
string cctype
+string cerrno
string climits
string cmath
string compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 55c79acff5a8f..2e0830dac6512 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -141,6 +141,7 @@ bitset algorithm
bitset atomic
bitset bit
bitset cctype
+bitset cerrno
bitset climits
bitset cmath
bitset compare
@@ -2160,6 +2161,7 @@ string algorithm
string atomic
string bit
string cctype
+string cerrno
string climits
string cmath
string compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 073f698786117..069f1c29ff051 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -47,6 +47,7 @@ bit cstdint
bit limits
bit version
bitset cctype
+bitset cerrno
bitset climits
bitset compare
bitset cstdint
@@ -136,6 +137,7 @@ cinttypes cstdint
cmath limits
cmath version
codecvt cctype
+codecvt cerrno
codecvt climits
codecvt clocale
codecvt compare
@@ -788,6 +790,7 @@ queue typeinfo
queue vector
queue version
random cctype
+random cerrno
random climits
random cmath
random compare
@@ -964,6 +967,7 @@ streambuf tuple
streambuf typeinfo
streambuf version
string cctype
+string cerrno
string climits
string compare
string cstdint
>From d840be60ee9486dff677f0b6217337d5b9b3a02e Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Jun 2026 16:16:49 +0800
Subject: [PATCH 5/6] Update synopsis comments
---
libcxx/include/string | 24 +++++++++----------
.../string.conversions/to_string.pass.cpp | 12 +++++-----
.../string.conversions/to_wstring.pass.cpp | 12 +++++-----
3 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index b5b74aecfb317..8372ca5f63294 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -540,12 +540,12 @@ float stof (const string& str, size_t* idx = nullptr);
double stod (const string& str, size_t* idx = nullptr);
long double stold(const string& str, size_t* idx = nullptr);
-string to_string(int val);
-string to_string(unsigned val);
-string to_string(long val);
-string to_string(unsigned long val);
-string to_string(long long val);
-string to_string(unsigned long long val);
+string to_string(int val); // constexpr since C++26
+string to_string(unsigned val); // constexpr since C++26
+string to_string(long val); // constexpr since C++26
+string to_string(unsigned long val); // constexpr since C++26
+string to_string(long long val); // constexpr since C++26
+string to_string(unsigned long long val); // constexpr since C++26
string to_string(float val);
string to_string(double val);
string to_string(long double val);
@@ -560,12 +560,12 @@ float stof (const wstring& str, size_t* idx = nullptr);
double stod (const wstring& str, size_t* idx = nullptr);
long double stold(const wstring& str, size_t* idx = nullptr);
-wstring to_wstring(int val);
-wstring to_wstring(unsigned val);
-wstring to_wstring(long val);
-wstring to_wstring(unsigned long val);
-wstring to_wstring(long long val);
-wstring to_wstring(unsigned long long val);
+wstring to_wstring(int val); // constexpr since C++26
+wstring to_wstring(unsigned val); // constexpr since C++26
+wstring to_wstring(long val); // constexpr since C++26
+wstring to_wstring(unsigned long val); // constexpr since C++26
+wstring to_wstring(long long val); // constexpr since C++26
+wstring to_wstring(unsigned long long val); // constexpr since C++26
wstring to_wstring(float val);
wstring to_wstring(double val);
wstring to_wstring(long double 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 a36d21592b08d..fb08efd17c82c 100644
--- a/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_string.pass.cpp
@@ -8,12 +8,12 @@
// <string>
-// string to_string(int val);
-// string to_string(unsigned val);
-// string to_string(long val);
-// string to_string(unsigned long val);
-// string to_string(long long val);
-// string to_string(unsigned long long val);
+// string to_string(int val); // constexpr since C++26
+// string to_string(unsigned val); // constexpr since C++26
+// string to_string(long val); // constexpr since C++26
+// string to_string(unsigned long val); // constexpr since C++26
+// string to_string(long long val); // constexpr since C++26
+// string to_string(unsigned long long val); // constexpr since C++26
// string to_string(float val);
// string to_string(double val);
// string to_string(long double val);
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 22d06bffb84b8..a8f691a2ff4cd 100644
--- a/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
+++ b/libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp
@@ -10,12 +10,12 @@
// <string>
-// wstring to_wstring(int val);
-// wstring to_wstring(unsigned val);
-// wstring to_wstring(long val);
-// wstring to_wstring(unsigned long val);
-// wstring to_wstring(long long val);
-// wstring to_wstring(unsigned long long val);
+// wstring to_wstring(int val); // constexpr since C++26
+// wstring to_wstring(unsigned val); // constexpr since C++26
+// wstring to_wstring(long val); // constexpr since C++26
+// wstring to_wstring(unsigned long val); // constexpr since C++26
+// wstring to_wstring(long long val); // constexpr since C++26
+// wstring to_wstring(unsigned long long val); // constexpr since C++26
// wstring to_wstring(float val);
// wstring to_wstring(double val);
// wstring to_wstring(long double val);
>From 0b727e696d32f30e8790fc098fae4770d550d163 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Jun 2026 16:24:15 +0800
Subject: [PATCH 6/6] Fixup `__to_basic_string`
---
libcxx/include/string | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index 8372ca5f63294..c600ff4af80ab 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3832,10 +3832,17 @@ _LIBCPP_HIDE_FROM_ABI constexpr _String __integer_to_string(_Integer __val) {
}
template <class _CharT, class _Integer>
-_LIBCPP_HIDE_FROM_ABI constexpr string __to_basic_string(_Integer __val) {
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT> __to_basic_string(_Integer __val) {
# ifdef _LIBCPP_PREFERRED_OVERLOAD
if !consteval {
- return std::to_string(__val);
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+ if constexpr (is_same_v<_CharT, wchar_t>) {
+ return std::to_wstring(__val);
+ } else
+# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+ {
+ return std::to_string(__val);
+ }
} else
# endif // _LIBCPP_PREFERRED_OVERLOAD
{
More information about the libcxx-commits
mailing list