[libcxx-commits] [libcxx] wip: [libcxx][format] P3391R2: `constexpr` `std::format` (PR #228535)
Lucas Mellone via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Oct 7 05:01:51 PDT 2026
https://github.com/lknknm updated https://github.com/llvm/llvm-project/pull/228535
>From fb9d5ee3a740c5622f7095a060c8183e50119f66 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 19:19:44 +0200
Subject: [PATCH 1/6] initial additions
---
libcxx/include/__format/format_functions.h | 6 +++---
libcxx/include/string | 24 +++++++++++-----------
libcxx/src/string.cpp | 24 +++++++++++-----------
3 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 8f214a493a49e..727fbb1c6ff83 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -351,15 +351,15 @@ struct __dynamic_format_string {
friend struct basic_format_string;
public:
- _LIBCPP_HIDE_FROM_ABI __dynamic_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __dynamic_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
__dynamic_format_string(const __dynamic_format_string&) = delete;
__dynamic_format_string& operator=(const __dynamic_format_string&) = delete;
};
-_LIBCPP_HIDE_FROM_ABI inline __dynamic_format_string<char> dynamic_format(string_view __fmt) noexcept { return __fmt; }
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline __dynamic_format_string<char> dynamic_format(string_view __fmt) noexcept { return __fmt; }
# if _LIBCPP_HAS_WIDE_CHARACTERS
-_LIBCPP_HIDE_FROM_ABI inline __dynamic_format_string<wchar_t> dynamic_format(wstring_view __fmt) noexcept {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline __dynamic_format_string<wchar_t> dynamic_format(wstring_view __fmt) noexcept {
return __fmt;
}
# endif
diff --git a/libcxx/include/string b/libcxx/include/string
index a27f9344916d1..ff6ea409bd53f 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -3825,12 +3825,12 @@ 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);
-[[__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);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(int __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(long long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned long long __val);
[[__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);
@@ -3849,12 +3849,12 @@ 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);
-[[__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);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(int __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(long long __val);
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned long long __val);
[[__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/src/string.cpp b/libcxx/src/string.cpp
index b55f9ff5c9a43..79675db7d5065 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -342,20 +342,20 @@ S i_to_string(V v) {
} // 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); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(int val) { return i_to_string< string>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(long val) { return i_to_string< string>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(long long val) { return i_to_string< string>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned val) { return i_to_string< string>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned long val) { return i_to_string< string>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 string to_string(unsigned long long val) { return i_to_string< 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); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(int val) { return i_to_string<wstring>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(long val) { return i_to_string<wstring>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
+_LIBCPP_CONSTEXPR_SINCE_CXX26 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
#endif
string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
>From ea3b44a9465e8b03f17a50e62d827d2ded41a92d Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 19:27:08 +0200
Subject: [PATCH 2/6] add: mark P3391R2 as Complete
---
libcxx/docs/Status/Cxx26Papers.csv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index f3cdf8c53bab4..ef9e5d5c38f82 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)","|Complete|","24","`#171292 <https://github.com/llvm/llvm-project/issues/171292>`__",""
"`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>`__",""
>From 8842de8059d6b1665a6a5b879206526c0dd71672 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 19:35:18 +0200
Subject: [PATCH 3/6] add: constexpr to vformat_to
---
libcxx/include/__format/format_functions.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 727fbb1c6ff83..3019fdbb167a0 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -425,13 +425,14 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(_OutIt __out_it,
// https://reviews.llvm.org/D110499#inline-1180704
// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
template <output_iterator<const char&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
>From 9a8811fd09b1600724f59c8455477e638475cbb1 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 20:01:23 +0200
Subject: [PATCH 4/6] fewer other updates
---
libcxx/include/__format/format_functions.h | 21 +++++++++++----------
libcxx/include/format | 4 ++--
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 3019fdbb167a0..2cdcf79b05bf2 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -439,14 +439,14 @@ vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
# endif
template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_wformat_args(__args...));
}
@@ -493,7 +493,8 @@ template <class _CharT>
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
+vformat(string_view __fmt, format_args __args) {
auto __result = __format::__try_constant_folding(__fmt, __args);
if (__result.has_value())
return *std::move(__result);
@@ -506,7 +507,7 @@ template <class = void>
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
vformat(wstring_view __fmt, wformat_args __args) {
auto __result = __format::__try_constant_folding(__fmt, __args);
if (__result.has_value())
@@ -518,14 +519,14 @@ vformat(wstring_view __fmt, wformat_args __args) {
# endif
template <class... _Args>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
format(format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(__fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class... _Args>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
format(wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(__fmt.get(), std::make_wformat_args(__args...));
}
@@ -544,14 +545,14 @@ __vformat_to_n(_OutIt __out_it,
}
template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<format_context>(std::move(__out_it), __n, __fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<wformat_context>(std::move(__out_it), __n, __fmt.get(), std::make_wformat_args(__args...));
}
@@ -566,14 +567,14 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt,
}
template <class... _Args>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_format_args(__args...)});
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class... _Args>
-[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
+[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)});
}
diff --git a/libcxx/include/format b/libcxx/include/format
index d89c8d8b0ae89..fa7136b6c44a8 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -179,10 +179,10 @@ namespace std {
template<class Context, class... Args> struct format-arg-store; // exposition only
template<class Context = format_context, class... Args>
- format-arg-store<Context, Args...>
+ constexpr format-arg-store<Context, Args...>
make_format_args(Args&... args);
template<class... Args>
- format-arg-store<wformat_context, Args...>
+ constexpr format-arg-store<wformat_context, Args...>
make_wformat_args(Args&... args);
// [format.error], class format_error
>From f0881ce8ef75f34201b6cdcd37fe4792162898af Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 20:07:37 +0200
Subject: [PATCH 5/6] add: constexpr since C++26 comments
---
libcxx/include/format | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/format b/libcxx/include/format
index fa7136b6c44a8..5f83ef33e5642 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -47,7 +47,7 @@ namespace std {
basic_string_view<charT> str; // exposition-only
public:
- dynamic-format-string(basic_string_view<charT> s) noexcept : str(s) {}
+ dynamic-format-string(basic_string_view<charT> s) noexcept : str(s) {} // constexpr since C++26
dynamic-format-string(const dynamic-format-string&) = delete;
dynamic-format-string& operator=(const dynamic-format-string&) = delete;
@@ -62,32 +62,32 @@ namespace std {
// [format.functions], formatting functions
template<class... Args>
- string format(format-string<Args...> fmt, Args&&... args);
+ string format(format-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class... Args>
- wstring format(wformat-string<Args...> fmt, Args&&... args);
+ wstring format(wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class... Args>
string format(const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class... Args>
wstring format(const locale& loc, wformat-string<Args...> fmt, Args&&... args);
- string vformat(string_view fmt, format_args args);
- wstring vformat(wstring_view fmt, wformat_args args);
+ string vformat(string_view fmt, format_args args); // constexpr since C++26
+ wstring vformat(wstring_view fmt, wformat_args args); // constexpr since C++26
string vformat(const locale& loc, string_view fmt, format_args args);
wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
template<class Out, class... Args>
- Out format_to(Out out, format-string<Args...> fmt, Args&&... args);
+ Out format_to(Out out, format-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class Out, class... Args>
- Out format_to(Out out, wformat-string<Args...> fmt, Args&&... args);
+ Out format_to(Out out, wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, wformat-string<Args...> fmt, Args&&... args);
template<class Out>
- Out vformat_to(Out out, string_view fmt, format_args args);
+ Out vformat_to(Out out, string_view fmt, format_args args); // constexpr since C++26
template<class Out>
- Out vformat_to(Out out, wstring_view fmt, wformat_args args);
+ Out vformat_to(Out out, wstring_view fmt, wformat_args args); // constexpr since C++26
template<class Out>
Out vformat_to(Out out, const locale& loc, string_view fmt,
format_args char> args);
@@ -101,10 +101,10 @@ namespace std {
};
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
- format-string<Args...> fmt, Args&&... args);
+ format-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
- wformat-string<Args...> fmt, Args&&... args);
+ wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, format-string<Args...> fmt,
@@ -115,9 +115,9 @@ namespace std {
Args&&... args);
template<class... Args>
- size_t formatted_size(format-string<Args...> fmt, Args&&... args);
+ size_t formatted_size(format-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class... Args>
- size_t formatted_size(wformat-string<Args...> fmt, Args&&... args);
+ size_t formatted_size(wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
template<class... Args>
size_t formatted_size(const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class... Args>
>From eb506961302e60dcb0f86252aae9730ccb3a93c9 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 7 Oct 2026 14:01:35 +0200
Subject: [PATCH 6/6] split: remove constexpr from format functions for now
---
libcxx/docs/Status/Cxx26Papers.csv | 2 +-
libcxx/include/__format/format_functions.h | 32 ++++++++++------------
libcxx/include/format | 30 ++++++++++----------
3 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index ef9e5d5c38f82..2aa7969b3cd10 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)","|Complete|","24","`#171292 <https://github.com/llvm/llvm-project/issues/171292>`__",""
+"`P3391R2 <https://wg21.link/P3391R2>`__","``constexpr`` ``std::format``","2025-11 (Kona)","|Partial|","24","`#171292 <https://github.com/llvm/llvm-project/issues/171292>`__",""
"`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/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 2cdcf79b05bf2..8f214a493a49e 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -351,15 +351,15 @@ struct __dynamic_format_string {
friend struct basic_format_string;
public:
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __dynamic_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
+ _LIBCPP_HIDE_FROM_ABI __dynamic_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
__dynamic_format_string(const __dynamic_format_string&) = delete;
__dynamic_format_string& operator=(const __dynamic_format_string&) = delete;
};
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline __dynamic_format_string<char> dynamic_format(string_view __fmt) noexcept { return __fmt; }
+_LIBCPP_HIDE_FROM_ABI inline __dynamic_format_string<char> dynamic_format(string_view __fmt) noexcept { return __fmt; }
# if _LIBCPP_HAS_WIDE_CHARACTERS
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline __dynamic_format_string<wchar_t> dynamic_format(wstring_view __fmt) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline __dynamic_format_string<wchar_t> dynamic_format(wstring_view __fmt) noexcept {
return __fmt;
}
# endif
@@ -425,28 +425,27 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(_OutIt __out_it,
// https://reviews.llvm.org/D110499#inline-1180704
// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
template <output_iterator<const char&> _OutIt>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
-vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
# endif
template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_wformat_args(__args...));
}
@@ -493,8 +492,7 @@ template <class _CharT>
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
-vformat(string_view __fmt, format_args __args) {
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
auto __result = __format::__try_constant_folding(__fmt, __args);
if (__result.has_value())
return *std::move(__result);
@@ -507,7 +505,7 @@ vformat(string_view __fmt, format_args __args) {
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
vformat(wstring_view __fmt, wformat_args __args) {
auto __result = __format::__try_constant_folding(__fmt, __args);
if (__result.has_value())
@@ -519,14 +517,14 @@ vformat(wstring_view __fmt, wformat_args __args) {
# endif
template <class... _Args>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
format(format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(__fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class... _Args>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
format(wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(__fmt.get(), std::make_wformat_args(__args...));
}
@@ -545,14 +543,14 @@ __vformat_to_n(_OutIt __out_it,
}
template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<format_context>(std::move(__out_it), __n, __fmt.get(), std::make_format_args(__args...));
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
+_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<wformat_context>(std::move(__out_it), __n, __fmt.get(), std::make_wformat_args(__args...));
}
@@ -567,14 +565,14 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt,
}
template <class... _Args>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_format_args(__args...)});
}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class... _Args>
-[[nodiscard]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
+[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)});
}
diff --git a/libcxx/include/format b/libcxx/include/format
index 5f83ef33e5642..d89c8d8b0ae89 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -47,7 +47,7 @@ namespace std {
basic_string_view<charT> str; // exposition-only
public:
- dynamic-format-string(basic_string_view<charT> s) noexcept : str(s) {} // constexpr since C++26
+ dynamic-format-string(basic_string_view<charT> s) noexcept : str(s) {}
dynamic-format-string(const dynamic-format-string&) = delete;
dynamic-format-string& operator=(const dynamic-format-string&) = delete;
@@ -62,32 +62,32 @@ namespace std {
// [format.functions], formatting functions
template<class... Args>
- string format(format-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ string format(format-string<Args...> fmt, Args&&... args);
template<class... Args>
- wstring format(wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ wstring format(wformat-string<Args...> fmt, Args&&... args);
template<class... Args>
string format(const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class... Args>
wstring format(const locale& loc, wformat-string<Args...> fmt, Args&&... args);
- string vformat(string_view fmt, format_args args); // constexpr since C++26
- wstring vformat(wstring_view fmt, wformat_args args); // constexpr since C++26
+ string vformat(string_view fmt, format_args args);
+ wstring vformat(wstring_view fmt, wformat_args args);
string vformat(const locale& loc, string_view fmt, format_args args);
wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
template<class Out, class... Args>
- Out format_to(Out out, format-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ Out format_to(Out out, format-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
- Out format_to(Out out, wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ Out format_to(Out out, wformat-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, wformat-string<Args...> fmt, Args&&... args);
template<class Out>
- Out vformat_to(Out out, string_view fmt, format_args args); // constexpr since C++26
+ Out vformat_to(Out out, string_view fmt, format_args args);
template<class Out>
- Out vformat_to(Out out, wstring_view fmt, wformat_args args); // constexpr since C++26
+ Out vformat_to(Out out, wstring_view fmt, wformat_args args);
template<class Out>
Out vformat_to(Out out, const locale& loc, string_view fmt,
format_args char> args);
@@ -101,10 +101,10 @@ namespace std {
};
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
- format-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ format-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
- wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ wformat-string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, format-string<Args...> fmt,
@@ -115,9 +115,9 @@ namespace std {
Args&&... args);
template<class... Args>
- size_t formatted_size(format-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ size_t formatted_size(format-string<Args...> fmt, Args&&... args);
template<class... Args>
- size_t formatted_size(wformat-string<Args...> fmt, Args&&... args); // constexpr since C++26
+ size_t formatted_size(wformat-string<Args...> fmt, Args&&... args);
template<class... Args>
size_t formatted_size(const locale& loc, format-string<Args...> fmt, Args&&... args);
template<class... Args>
@@ -179,10 +179,10 @@ namespace std {
template<class Context, class... Args> struct format-arg-store; // exposition only
template<class Context = format_context, class... Args>
- constexpr format-arg-store<Context, Args...>
+ format-arg-store<Context, Args...>
make_format_args(Args&... args);
template<class... Args>
- constexpr format-arg-store<wformat_context, Args...>
+ format-arg-store<wformat_context, Args...>
make_wformat_args(Args&... args);
// [format.error], class format_error
More information about the libcxx-commits
mailing list