From: Ivan Lazaric Date: Fri, 15 May 2026 09:06:46 +0000 (+0200) Subject: libstdc++: mark integer std::to_(w)string constexpr X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=5ce76a8adbc008fa11281ae996eb8fd40353f601;p=thirdparty%2Fgcc.git libstdc++: mark integer std::to_(w)string constexpr In C++26 paper P3391, "constexpr formatting", has been adopted, part of which marks std::to_string & std::to_wstring for integers as constexpr. The __cpp_lib_constexpr_string FTM value is updated per resolution of LWG4531, "Should there be a feature-test macro update for constexpr std::to_(w)string?". Since pre-cxx11 copy-on-write string is not constexpr-enabled, restricting this constexpr-ification to cxx11 ABI strings. libstdc++-v3/ChangeLog: * include/bits/version.def (constexpr_string): Bump to 202511. * include/bits/version.h: Regenerate. * include/bits/basic_string.h (std::to_string, std::to_wstring) [__glibcxx_constexpr_string >= 202511L]: Mark as constexpr. * testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc: New test. * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc: New test. * testsuite/21_strings/basic_string/cons/char/constexpr.cc: Update __cpp_lib_constexpr_string check. * testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc: Likewise. * testsuite/21_strings/basic_string/version.cc: Add check for value of __cpp_lib_constexpr_string in C++26. Co-authored-by: Tomasz Kamiński Reviewed-by: Jonathan Wakely Reviewed-by: Nathan Myers Signed-off-by: Tomasz Kamiński --- diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 23e6979f03d..65d92ebfbcf 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -4607,11 +4607,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { return std::stod(__str, __idx); } #endif +#if __glibcxx_constexpr_string >= 202511L +# define _GLIBCXX_TO_STRING_CONSTEXPR constexpr +#else +# define _GLIBCXX_TO_STRING_CONSTEXPR inline +#endif + // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 1261. Insufficient overloads for to_string / to_wstring _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(int __val) #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_INT__) <= 32 noexcept // any 32-bit value fits in the SSO buffer @@ -4630,7 +4636,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(unsigned __val) #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_INT__) <= 32 noexcept // any 32-bit value fits in the SSO buffer @@ -4646,7 +4652,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(long __val) #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_LONG__) <= 32 noexcept // any 32-bit value fits in the SSO buffer @@ -4665,7 +4671,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(unsigned long __val) #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_LONG__) <= 32 noexcept // any 32-bit value fits in the SSO buffer @@ -4681,7 +4687,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(long long __val) { const bool __neg = __val < 0; @@ -4698,7 +4704,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } _GLIBCXX_NODISCARD - inline string + _GLIBCXX_TO_STRING_CONSTEXPR string to_string(unsigned long long __val) { const auto __len = __detail::__to_chars_len(__val); @@ -4922,32 +4928,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #pragma GCC diagnostic pop _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(int __val) { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(unsigned __val) { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(long __val) { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(unsigned long __val) { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(long long __val) { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD - inline wstring + _GLIBCXX_TO_STRING_CONSTEXPR wstring to_wstring(unsigned long long __val) { return std::__to_wstring_numeric(std::to_string(__val)); } @@ -4968,6 +4974,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { return std::__to_wstring_numeric(std::to_string(__val)); } #endif #endif // _GLIBCXX_USE_WCHAR_T +#undef _GLIBCXX_TO_STRING_CONSTEXPR _GLIBCXX_END_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 97f7d686519..ea8560778e5 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1398,6 +1398,14 @@ ftms = { ftms = { name = constexpr_string; + // 202511 LWG4531 Should there be a feature-test macro update for constexpr std::to_(w)string? + // P3391R2 constexpr std::format + values = { + v = 202511; + cxxmin = 26; + hosted = yes; + cxx11abi = yes; + }; values = { v = 201907; cxxmin = 20; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 33eecbfb83b..59d5d9217d7 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1542,7 +1542,12 @@ #undef __glibcxx_want_constexpr_flat_set #if !defined(__cpp_lib_constexpr_string) -# if (__cplusplus >= 202002L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED && (defined(__glibcxx_is_constant_evaluated)) +# if (__cplusplus > 202302L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED +# define __glibcxx_constexpr_string 202511L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string) +# define __cpp_lib_constexpr_string 202511L +# endif +# elif (__cplusplus >= 202002L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED && (defined(__glibcxx_is_constant_evaluated)) # define __glibcxx_constexpr_string 201907L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string) # define __cpp_lib_constexpr_string 201907L diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc index 7822c89497b..34abfe60bc5 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc @@ -6,8 +6,8 @@ #ifndef __cpp_lib_constexpr_string # error "Feature-test macro for constexpr std::string missing in " -#elif __cpp_lib_constexpr_string != 201907L -# error "Feature-test macro for constexpr std::string has wrong value in " +#elif __cpp_lib_constexpr_string < 201907L +# error "Feature-test macro for constexpr std::string has too small value in " #endif #include diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc index 44c8391ebc2..59d5ee270cc 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc @@ -6,8 +6,8 @@ #ifndef __cpp_lib_constexpr_string # error "Feature-test macro for constexpr std::string missing in " -#elif __cpp_lib_constexpr_string != 201907L -# error "Feature-test macro for constexpr std::string has wrong value in " +#elif __cpp_lib_constexpr_string < 201907L +# error "Feature-test macro for constexpr std::string too small value in " #endif #include diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc new file mode 100644 index 00000000000..1b5a616df54 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc @@ -0,0 +1,64 @@ +// { dg-do compile { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include +#include +#include + +template +constexpr void +test() +{ + using namespace std; + string res; + T value; + + value = 0; + res = to_string(value); + VERIFY( res == "0" ); + + value = 1; + res = to_string(value); + VERIFY( res == "1" ); + + value = 10; + res = to_string(value); + VERIFY( res == "10" ); + + value = 3000; + res = to_string(value); + VERIFY( res == "3000" ); + + value = 32767; + res = to_string(value); + VERIFY( res == "32767" ); + + if (is_unsigned_v) + return; + + value = -1; + res = to_string(value); + VERIFY( res == "-1" ); + + value = -40; + res = to_string(value); + VERIFY( res == "-40" ); + + value = -32768; + res = to_string(value); + VERIFY( res == "-32768" ); +} + +constexpr bool +test_all() +{ + test(); + test(); + test(); + test(); + test(); + test(); + return true; +} + +static_assert(test_all()); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc new file mode 100644 index 00000000000..f884fc61ff5 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc @@ -0,0 +1,64 @@ +// { dg-do compile { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include +#include +#include + +template +constexpr void +test() +{ + using namespace std; + wstring res; + T value; + + value = 0; + res = to_wstring(value); + VERIFY( res == L"0" ); + + value = 1; + res = to_wstring(value); + VERIFY( res == L"1" ); + + value = 10; + res = to_wstring(value); + VERIFY( res == L"10" ); + + value = 3000; + res = to_wstring(value); + VERIFY( res == L"3000" ); + + value = 32767; + res = to_wstring(value); + VERIFY( res == L"32767" ); + + if (is_unsigned_v) + return; + + value = -1; + res = to_wstring(value); + VERIFY( res == L"-1" ); + + value = -40; + res = to_wstring(value); + VERIFY( res == L"-40" ); + + value = -32768; + res = to_wstring(value); + VERIFY( res == L"-32768" ); +} + +constexpr bool +test_all() +{ + test(); + test(); + test(); + test(); + test(); + test(); + return true; +} + +static_assert(test_all()); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/version.cc b/libstdc++-v3/testsuite/21_strings/basic_string/version.cc index 71dd4dfb67f..b0cdf04274e 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/version.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/version.cc @@ -25,3 +25,15 @@ # endif # endif #endif + +#if __cplusplus > 202302L +# if _GLIBCXX_USE_CXX11_ABI +# if __cpp_lib_constexpr_string != 202511L +# error "Feature-test macro for constexpr std::string has wrong value for C++20 in " +# endif +# else // COW strings +# if __cpp_lib_constexpr_string != 201811L +# error "Feature-test macro for constexpr std::string has wrong value for C++20 in " +# endif +# endif +#endif