-
Notifications
You must be signed in to change notification settings - Fork 14.3k
WIP - [libc++][string] P2587R3: to_string
or not to_string
#78100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
WIP - [libc++][string] P2587R3: to_string
or not to_string
#78100
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
to_string
or not to_string
to_string
or not to_string
7453327
to
607f643
Compare
Some notes:
|
to_string
or not to_string
to_string
or not to_string
@llvm/pr-subscribers-libcxx Author: Hristo Hristov (H-G-Hristov) ChangesImplements: https://wg21.link/P2587R3 Patch is 25.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/78100.diff 9 Files Affected:
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 893a3b13ca06e0..d17a056e688c02 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -380,7 +380,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_string_resize_and_overwrite`` ``202110L``
--------------------------------------------------- -----------------
- ``__cpp_lib_to_string`` *unimplemented*
+ ``__cpp_lib_to_string`` ``202306L``
--------------------------------------------------- -----------------
``__cpp_lib_to_underlying`` ``202102L``
--------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 5701717f39766c..6e9ca8f4e890a1 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -1,7 +1,7 @@
"Paper #","Group","Paper Name","Meeting","Status","First released version","Labels"
"`P2497R0 <https://wg21.link/P2497R0>`__","LWG","Testing for success or failure of ``<charconv>`` functions","Varna June 2023","|Complete|","18.0",""
"`P2592R3 <https://wg21.link/P2592R3>`__","LWG","Hashing support for ``std::chrono`` value classes","Varna June 2023","","",""
-"`P2587R3 <https://wg21.link/P2587R3>`__","LWG","``to_string`` or not ``to_string``","Varna June 2023","","","|format|"
+"`P2587R3 <https://wg21.link/P2587R3>`__","LWG","``to_string`` or not ``to_string``","Varna June 2023","|Complete|","18.0","|format|"
"`P2562R1 <https://wg21.link/P2562R1>`__","LWG","``constexpr`` Stable Sorting","Varna June 2023","","",""
"`P2545R4 <https://wg21.link/P2545R4>`__","LWG","Read-Copy Update (RCU)","Varna June 2023","","",""
"`P2530R3 <https://wg21.link/P2530R3>`__","LWG","Hazard Pointers for C++26","Varna June 2023","","",""
diff --git a/libcxx/include/version b/libcxx/include/version
index c96647894dce63..efb7f56f74966d 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -473,7 +473,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
# define __cpp_lib_stdatomic_h 202011L
# define __cpp_lib_string_contains 202011L
# define __cpp_lib_string_resize_and_overwrite 202110L
-// # define __cpp_lib_to_string 202306L
+# define __cpp_lib_to_string 202306L
# define __cpp_lib_to_underlying 202102L
// # define __cpp_lib_tuple_like 202207L
# define __cpp_lib_unreachable 202202L
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index cf07b3ef1ef270..630f76d4d878c5 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>
@@ -247,6 +248,36 @@ long double stold(const wstring& str, size_t* idx) { return as_float<long double
// to_string
+#if _LIBCPP_STD_VER >= 26
+
+string to_string(int val) { return std::format("{}", val); }
+string to_string(long val) { return std::format("{}", val); }
+string to_string(long long val) { return std::format("{}", val); }
+string to_string(unsigned val) { return std::format("{}", val); }
+string to_string(unsigned long val) { return std::format("{}", val); }
+string to_string(unsigned long long val) { return std::format("{}", val); }
+
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+wstring to_wstring(int val) { return std::format(L"{}", val); }
+wstring to_wstring(long val) { return std::format(L"{}", val); }
+wstring to_wstring(long long val) { return std::format(L"{}", val); }
+wstring to_wstring(unsigned val) { return std::format(L"{}", val); }
+wstring to_wstring(unsigned long val) { return std::format(L"{}", val); }
+wstring to_wstring(unsigned long long val) { return std::format(L"{}", val); }
+# endif
+
+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 {
// as_string
@@ -283,7 +314,7 @@ struct initial_string<string> {
}
};
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <>
struct initial_string<wstring> {
wstring operator()() const {
@@ -296,13 +327,13 @@ struct initial_string<wstring> {
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);
inline wide_printf get_swprintf() {
-# ifndef _LIBCPP_MSVCRT
+# ifndef _LIBCPP_MSVCRT
return swprintf;
-# else
+# else
return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);
-# endif
+# endif
}
-#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <typename S, typename V>
S i_to_string(V v) {
@@ -325,23 +356,25 @@ 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); }
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# ifndef _LIBCPP_HAS_NO_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); }
-#endif
+# endif
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); }
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# ifndef _LIBCPP_HAS_NO_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 b5770f8fbe65d3..b4e8927cd113df 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
@@ -364,17 +364,11 @@
# error "__cpp_lib_string_view should have the value 201803L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_to_string
-# error "__cpp_lib_to_string should be defined in c++23"
-# endif
-# if __cpp_lib_to_string != 202306L
-# error "__cpp_lib_to_string should have the value 202306L in c++23"
-# 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++23"
+# endif
+# if __cpp_lib_to_string != 202306L
+# error "__cpp_lib_to_string should have the value 202306L in c++23"
# endif
#elif TEST_STD_VER > 23
@@ -462,17 +456,11 @@
# error "__cpp_lib_string_view should have the value 201803L 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 d5a0839b30f824..e01a781b2f0682 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
@@ -5706,17 +5706,11 @@
# endif
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_to_string
-# error "__cpp_lib_to_string should be defined in c++23"
-# endif
-# if __cpp_lib_to_string != 202306L
-# error "__cpp_lib_to_string should have the value 202306L in c++23"
-# 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++23"
+# endif
+# if __cpp_lib_to_string != 202306L
+# error "__cpp_lib_to_string should have the value 202306L in c++23"
# endif
# ifndef __cpp_lib_to_underlying
@@ -7474,17 +7468,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 4731a072e89108..87ab89c39ffe7f 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 fff5ede848b57a..6c3a5825c43aa0 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());
...
[truncated]
|
…to_string` as C++26 (#93255) [P2845R8](https://wg21.link/P2845R8) "Formatting of `std::filesystem::path`" and [P2587R3](https://wg21.link/P2587R3) "`to_string` or not `to_string`" are C++26 features, so they should be marked accordingly in `generate_feature_test_macro_components.py`. I verified that without my changes, running the script produced no edits. Then with my changes, I ran the script to regenerate all files, with no other manual edits. Found while running libc++'s tests with MSVC's STL, which noticed this because it's currently a C++23-only implementation. Note that @H-G-Hristov has a draft implementation of P2587R3: #78100
…to_string` as C++26 (llvm#93255) [P2845R8](https://wg21.link/P2845R8) "Formatting of `std::filesystem::path`" and [P2587R3](https://wg21.link/P2587R3) "`to_string` or not `to_string`" are C++26 features, so they should be marked accordingly in `generate_feature_test_macro_components.py`. I verified that without my changes, running the script produced no edits. Then with my changes, I ran the script to regenerate all files, with no other manual edits. Found while running libc++'s tests with MSVC's STL, which noticed this because it's currently a C++23-only implementation. Note that @H-G-Hristov has a draft implementation of P2587R3: llvm#78100
Can I take this with your test cases reused? I have some thoughts on separately compiled functions, but I'm a bit too unfamiliar with test cases. |
IMO we shouldn't do this at the moment. |
@frederick-vs-ja In case this PR is open for business again. Please feel free to take it if you like. I'll resolve the merge conflicts and I'll make the PR up-to-date now. |
928351c
to
49b2559
Compare
IMO we should discuss whether we can just backport this to all standards modes. The committee seems to be fine with this being hypothetically breaking after all. That would allow us to just update the definition in the dylib and have the FTM set when a dylib that is new enough is used instead of introducing new symbols. (FWiW I also don't understand why you're introducing both an underscored version and an inline namespace) |
Thanks. I guess by the time when we could implement this, the final version will look different. |
libcxx/include/string
Outdated
_LIBCPP_EXPORTED_FROM_ABI string __to_string(double __val); | ||
_LIBCPP_EXPORTED_FROM_ABI string __to_string(long double __val); | ||
|
||
inline _LIBCPP_HIDE_FROM_ABI string to_string(float __val) { return std::__to_string(__val); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use to_chars
here to avoid changing ABI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also my branch: https://github.com/frederick-vs-ja/llvm-project/tree/p2587r3. Do you think my approach viable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
frederick-vs-ja@78f270a - this looks like a better alternative to my experiments in implementing this.
BTW I wanted to get the CI green with what I have so far. I still haven't.
Would you like to update this PR with your changes or wait for whenever we can/decide to pursue this paper further or create a new PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it seems it may take quite a while before to_chars
will be done I don't think we need to spend time now to fix the CI, this will be outdated once we can pursue this patch.
That is unless somebody else volunteers to implement to_chars
long double. It is on my TODO list, but not at a high priority. Realistically I don't expect to work on it this year.
3b59c59
to
df6fd5b
Compare
df6fd5b
to
c6c25dc
Compare
Implements: https://wg21.link/P2587R3
Closes #105359
NOTE: The PR is on hold because of #78100 (comment)