[PATCH] libstdc++: implement constexpr std::format

2026-03-10 Thread Ivan Lazaric
This patch implements constexpr formatting from P3391R2,
and introduces the constexpr_format feature-test macro.
Since pre-cxx11 cow_string is not constexpr-enabled,
only exposing the feature-test macro under cxx11 ABI.

Add `__format::__toupper_numeric` function that work in constexpr.
It is not fully general, but `` doesn't need all uppercasing.

Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
since it is a bit non-trivial to get it to work, and it is just an optimization.

Mark `basic_format_string` consteval constructor noexcept,
since exceptions are now constexpr, and the standard mandates
failure to parse to be non-catchable ill-formed.
https://eel.is/c++draft/format#fmt.string-3
> Remarks: A call to this function is not a core constant expression
> ([expr.const]) unless there exist args of types Args such that
> str is a format string for args.

Update some formatting tests to test constexpr as well,
and introduce a dedicated smoke test for constexpr formatting.

libstdc++-v3/include/ChangeLog:

* bits/version.def: Add constexpr_format.
* bits/version.h: Regenerate.
* std/format:
Expose constexpr_format feature-test macro,
constexpr-ify most functions, replace memcpy with ranges::copy.
(__format::__toupper_numeric): Define.
(__format::__do_vformat_to): Avoid using _Ptr_sink in constexpr.

libstdc++-v3/testsuite/ChangeLog:

* std/format/arguments/args_neg.cc: Diagnostics change.
* std/format/constexpr.cc: New test.
* std/format/debug.cc: Constexpr testing.
* std/format/functions/format.cc: Constexpr testing.
* std/format/functions/format_to.cc: Constexpr testing.
* std/format/functions/size.cc: Constexpr testing.
* std/format/ranges/format_kind.cc: Constexpr testing.
* std/format/ranges/formatter.cc: Constexpr testing.
* std/format/ranges/sequence.cc: Constexpr testing.
* std/format/runtime_format.cc: Constexpr testing.
* std/format/string.cc: Constexpr testing.
* std/format/tuple.cc: Constexpr testing.
* std/time/format/data_not_present_neg.cc: Diagnostics change.

Signed-off-by: Ivan Lazaric 
---
Rebased, no unmerged patches anymore
Restricted to CXX11 ABI
Guarding tests and constexpr-ification with __glibcxx_constexpr_format

 libstdc++-v3/include/bits/version.def |  12 +
 libstdc++-v3/include/bits/version.h   |   9 +
 libstdc++-v3/include/std/format   | 393 +++---
 .../std/format/arguments/args_neg.cc  |   4 +-
 .../testsuite/std/format/constexpr.cc | 166 
 libstdc++-v3/testsuite/std/format/debug.cc|  82 ++--
 .../testsuite/std/format/functions/format.cc  | 281 +++--
 .../std/format/functions/format_to.cc |  58 ++-
 .../testsuite/std/format/functions/size.cc|  23 +-
 .../std/format/ranges/format_kind.cc  |  15 +-
 .../testsuite/std/format/ranges/formatter.cc  |  37 +-
 .../testsuite/std/format/ranges/sequence.cc   |  64 ++-
 .../testsuite/std/format/runtime_format.cc|  25 +-
 libstdc++-v3/testsuite/std/format/string.cc   |  59 ++-
 libstdc++-v3/testsuite/std/format/tuple.cc|  70 +++-
 .../std/time/format/data_not_present_neg.cc   |   3 +-
 16 files changed, 914 insertions(+), 387 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index dbe95b8b79f..6a1ee0b0579 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1330,6 +1330,18 @@ ftms = {
   };
 };
 
+ftms = {
+  name = constexpr_format;
+  // 202511 P3391R2 constexpr std::format
+  no_stdname = true; // in progress
+  values = {
+v = 202511;
+cxxmin = 26;
+hosted = yes;
+cxx11abi = yes;
+  };
+};
+
 ftms = {
   name = format_uchar;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index eee99847490..f690c46c739 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1476,6 +1476,15 @@
 #endif /* !defined(__cpp_lib_format) */
 #undef __glibcxx_want_format
 
+#if !defined(__cpp_lib_constexpr_format)
+# if (__cplusplus >  202302L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED
+#  define __glibcxx_constexpr_format 202511L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_format)
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_constexpr_format) */
+#undef __glibcxx_want_constexpr_format
+
 #if !defined(__cpp_lib_format_uchar)
 # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
 #  define __glibcxx_format_uchar 202311L
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 4297bcc1007..bcbb5211227 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -39,6 +39,7 @@
 #define __glibcxx_want_format_ranges
 #define __glibcxx_want_forma

[PATCH] libstdc++: implement constexpr std::format

2026-03-05 Thread Ivan Lazaric
This patch implements constexpr formatting from P3391R2,
and introduces the constexpr_format feature-test macro.

This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.

Add `__format::__toupper_numeric` function that work in constexpr.
It is not fully general, but `` doesn't need all uppercasing.

Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
since it is a bit non-trivial to get it to work, and it is just an optimization.

Mark `basic_format_string` consteval constructor noexcept,
since exceptions are now constexpr, and the standard mandates
failure to parse to be non-catchable ill-formed.
https://eel.is/c++draft/format#fmt.string-3
> Remarks: A call to this function is not a core constant expression
> ([expr.const]) unless there exist args of types Args such that
> str is a format string for args.

Mark integer to_{,w}string functions constexpr.
Introduce constexpr tests for them.

Update some formatting tests to test constexpr as well,
and introduce a dedicated smoke test for constexpr formatting.

libstdc++-v3/include/ChangeLog:

* bits/basic_string.h:
Add _GLIBCXX26_CONSTEXPR to std::to_{,w}string.
* bits/version.def: Add constexpr_format.
* bits/version.h: Regenerate.
* std/format:
Expose constexpr_format feature-test macro,
pepper in _GLIBCXX26_CONSTEXPR, replace memcpy with ranges::copy.
(__format::__toupper_numeric): Define.
(__format::__do_vformat_to): Avoid using _Ptr_sink in constexpr.

libstdc++-v3/testsuite/ChangeLog:

* std/format/arguments/args_neg.cc: Diagnostics change.
* std/format/constexpr.cc: New test.
* std/format/debug.cc: Constexpr testing.
* std/format/functions/format.cc: Constexpr testing.
* std/format/functions/format_to.cc: Constexpr testing.
* std/format/functions/size.cc: Constexpr testing.
* std/format/ranges/format_kind.cc: Constexpr testing.
* std/format/ranges/formatter.cc: Constexpr testing.
* std/format/ranges/sequence.cc: Constexpr testing.
* std/format/runtime_format.cc: Constexpr testing.
* std/format/string.cc: Constexpr testing.
* std/format/tuple.cc: Constexpr testing.
* std/time/format/data_not_present_neg.cc: Diagnostics change.
* 
21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc:
New test.
* 
21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc:
New test.

Signed-off-by: Ivan Lazaric 
---
Rebased, only non-merged prerequisites are:
* libstdc++: Introduce __format::_Ptr_sink for contingous iterators.
* libstdc+: Eliminate usage of alloca for non-localized formatting

Added constexpr to std::to_{,w}string, added tests for them.
The couple existing tests I looked at don't allow for easy constexpr testing,
for example to_string_int.cc test depends on snprintf.

In current shape it's rather complete, might make sense to drop no_stdname
from the feature-test macro.


 libstdc++-v3/include/bits/basic_string.h  |  24 +-
 libstdc++-v3/include/bits/version.def |  11 +
 libstdc++-v3/include/bits/version.h   |   9 +
 libstdc++-v3/include/std/format   | 387 +++---
 .../char/to_string_constexpr.cc   |  63 +++
 .../wchar_t/to_wstring_constexpr.cc   |  63 +++
 .../std/format/arguments/args_neg.cc  |   4 +-
 .../testsuite/std/format/constexpr.cc | 156 +++
 libstdc++-v3/testsuite/std/format/debug.cc|  82 ++--
 .../testsuite/std/format/functions/format.cc  | 281 +++--
 .../std/format/functions/format_to.cc |  58 ++-
 .../testsuite/std/format/functions/size.cc|  23 +-
 .../std/format/ranges/format_kind.cc  |  15 +-
 .../testsuite/std/format/ranges/formatter.cc  |  37 +-
 .../testsuite/std/format/ranges/sequence.cc   |  64 ++-
 .../testsuite/std/format/runtime_format.cc|  17 +-
 libstdc++-v3/testsuite/std/format/string.cc   |  59 ++-
 libstdc++-v3/testsuite/std/format/tuple.cc|  70 +++-
 .../std/time/format/data_not_present_neg.cc   |   3 +-
 19 files changed, 1026 insertions(+), 400 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc
 create mode 100644 
libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc
 create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc

diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index 9bbe16507d0..1317b292335 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -4582,7 +4582,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   // DR 1261. Insufficent overloads for to_string / to_wstring
 
   _GLIBCXX_NODISCARD
-  inline string
+  inline _GLIBCXX26_CONSTEXPR string
   to_string(int __val)
 #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_I

[PATCH] libstdc++: implement constexpr std::format

2026-03-04 Thread Ivan Lazaric
This patch partially implements constexpr formatting from P3391R2,
and introduces the constexpr_format feature-test macro.

This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.

Add `__format::__toupper_numeric` function that work in constexpr.
It is not fully general, but `` doesn't need all uppercasing.

Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
since it is a bit non-trivial to get it to work, and it is just an optimization.

Mark `basic_format_string` consteval constructor noexcept,
since exceptions are now constexpr, and the standard mandates
failure to parse to be non-catchable ill-formed.
https://eel.is/c++draft/format#fmt.string-3
> Remarks: A call to this function is not a core constant expression
> ([expr.const]) unless there exist args of types Args such that
> str is a format string for args.

Some wide formatting relies on `__builtin_alloca` which doesn't work
in constexpr, changed it to go through regular allocation
and cleanup in constexpr.

Update some formatting tests to test constexpr as well,
and introduce a dedicated smoke test for constexpr formatting.

This patch is missing:
* constexpr to_{,w}string
* more constexpr tests

libstdc++-v3/ChangeLog:

* include/bits/version.def: Add constexpr_format.
* include/bits/version.h: Regenerate.
* include/std/format:
Pepper in _GLIBCXX26_CONSTEXPR, replace memcpy with ranges::copy,
avoid __builtin_alloca in constexpr wide formatting.
(__format::__toupper_numeric): Define.
(__format::__do_vformat_to):
Avoid using _Ptr_sink in constexpr.
* testsuite/std/format/arguments/args_neg.cc: Diagnostics change.
* testsuite/std/format/constexpr.cc: New test.
* testsuite/std/format/debug.cc: Constexpr testing.
* testsuite/std/format/functions/format.cc: Constexpr testing.
* testsuite/std/format/functions/format_to.cc: Constexpr testing.
* testsuite/std/format/functions/size.cc: Constexpr testing.
* testsuite/std/format/ranges/format_kind.cc: Constexpr testing.
* testsuite/std/format/ranges/formatter.cc: Constexpr testing.
* testsuite/std/format/ranges/sequence.cc: Constexpr testing.
* testsuite/std/format/runtime_format.cc: Constexpr testing.
* testsuite/std/format/string.cc: Constexpr testing.
* testsuite/std/format/tuple.cc: Constexpr testing.
* testsuite/std/time/format/data_not_present_neg.cc: Diagnostics change.

Signed-off-by: Ivan Lazaric 
---
Notable changes:

std/format/arguments/args_neg.cc & std/time/format/data_not_present_neg.cc:
touched up the diagnostics they expect.

Fixed up constexpr wide formatting, avoiding the __builtin_alloca
with regular allocation, and a unique_ptr-esque _Cleanup deallocation
on scope exit. Last remaining __builtin_alloca is in locale related path.
Testing constexpr wide formatting in both existing tests and
newly introduced constexpr.cc.

Rebased on top of untested fix mentioned in:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124145
This allows for constexpr tests related to exceptions,
enabled them in the existing tests I touched.

Marked basic_format_string constructor as noexcept,
so the exception blows up compilation and is not catchable.

Patches this is based on top of that aren't merged yet:
* libstdc++: Store basic_format_arg::handle in __format::_Arg_value
* libstdc++: Introduce __format::_Ptr_sink for contingous iterators.
* libstdc++: Remove UB in _Arg_value union alteranatives assigment
* PR c++/124145 mentioned fix
In case the base for this patch is becoming confusing, it can be found at:
https://github.com/ilazaric/gcc/tree/ilazaric/constexpr-formatting-base

One test I took a look at and didn't constexpr-ify:
std/format/parse_ctx.cc
I'm unsure it makes sense to constexpr-ify it,
as it runs into: https://eel.is/c++draft/format#parse.ctx-note-1
> Note: Any call to next_arg_id, check_arg_id, or check_dynamic_spec
> on an instance of basic_format_parse_context initialized using
> this constructor is not a core constant expression.

I am also noting not yet resolved LWG issue as relevant:
https://cplusplus.github.io/LWG/issue4531



 libstdc++-v3/include/bits/version.def |  11 +
 libstdc++-v3/include/bits/version.h   |   9 +
 libstdc++-v3/include/std/format   | 429 +++---
 .../std/format/arguments/args_neg.cc  |   4 +-
 .../testsuite/std/format/constexpr.cc | 156 +++
 libstdc++-v3/testsuite/std/format/debug.cc|  82 ++--
 .../testsuite/std/format/functions/format.cc  | 281 +++-
 .../std/format/functions/format_to.cc |  58 ++-
 .../testsuite/std/format/functions/size.cc|  23 +-
 .../std/format/ranges/format_kind.cc  |  15 +-
 .../testsuite/std/format/ranges/formatter.cc  |  37 +-
 .../testsuite/std/format/ranges/sequence.cc   |  64 ++-
 .../testsuite/std/format/runtime_format.cc|  17 +-
 libstdc++-v3/testsuite/std/format/strin

[PATCH] libstdc++: implement constexpr std::format

2026-02-26 Thread Ivan Lazaric
libstdc++: partially implement constexpr std::format

This patch partially implements constexpr formatting from P3391R2,
as such it does not define the __cpp_lib_constexpr_format feature-test macro.

This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.

Add `__format::__toupper` function that work in constexpr.
It is not fully general, but `` doesn't need all uppercasing.

Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
since it is a bit non-trivial to get it to work, and it is just an optimization.

Update some formatting tests to test constexpr as well,
and introduce a dedicated smoke test for constexpr formatting.

This patch is missing:
* wide constexpr formatting
* constexpr to_{,w}string
* more constexpr tests

libstdc++-v3/ChangeLog:

* include/std/format:
Pepper in _GLIBCXX26_CONSTEXPR, replace memcpy with ranges::copy.
(__format::__toupper): Define.
(__format::__do_vformat_to):
Avoid using _Ptr_sink in constexpr.
* testsuite/std/format/constexpr.cc: New test.
* testsuite/std/format/debug.cc: Constexpr testing.
* testsuite/std/format/functions/format.cc: Constexpr testing.
* testsuite/std/format/functions/format_to.cc: Constexpr testing.
* testsuite/std/format/functions/size.cc: Constexpr testing.
* testsuite/std/format/ranges/format_kind.cc: Constexpr testing.
* testsuite/std/format/ranges/formatter.cc: Constexpr testing.
* testsuite/std/format/ranges/sequence.cc: Constexpr testing.
* testsuite/std/format/runtime_format.cc: Constexpr testing.
* testsuite/std/format/string.cc: Constexpr testing.
* testsuite/std/format/tuple.cc: Constexpr testing.

Signed-off-by: Ivan Lazaric 
---
Updates to patch:
Replaced __memcpy with ranges::copy
Simplified __toupper as a switch
if (not) consteval replaced with std::is_constant_evaluated()
Rebased on top of your _M_access patch
Removed the version.{def,h} since this doesn't implement full paper
Cleaned up tests as suggested
Added a constexpr.cc test with c++26 target
Killed Counting_constexpr_sink, just going through _Ptr_sink

Regarding formatting of nullptr:
basic_format_arg(nullptr) will store a `const void*` ,
so `format(nullptr)` will actually go through `formatter`.

I've been testing with GLIBCXX_TESTSUITE_STDS=20,23,26,
two tests are failing in 26 now, both are testing compilation errors:
std/format/arguments/args_neg.cc
std/time/format/data_not_present_neg.cc
Haven't yet investigated.


 libstdc++-v3/include/std/format   | 388 +++---
 .../testsuite/std/format/constexpr.cc | 126 ++
 libstdc++-v3/testsuite/std/format/debug.cc| 105 +++--
 .../testsuite/std/format/functions/format.cc  | 265 +++-
 .../std/format/functions/format_to.cc |  63 ++-
 .../testsuite/std/format/functions/size.cc|  24 +-
 .../std/format/ranges/format_kind.cc  |  15 +-
 .../testsuite/std/format/ranges/formatter.cc  |  45 +-
 .../testsuite/std/format/ranges/sequence.cc   |  73 +++-
 .../testsuite/std/format/runtime_format.cc|  18 +-
 libstdc++-v3/testsuite/std/format/string.cc   | 230 +++
 libstdc++-v3/testsuite/std/format/tuple.cc|  78 +++-
 12 files changed, 967 insertions(+), 463 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 4f0b0f377c6..b5670d0ec32 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -128,6 +128,7 @@ namespace __format
 struct _Runtime_format_string
 {
   [[__gnu__::__always_inline__]]
+  _GLIBCXX26_CONSTEXPR
   _Runtime_format_string(basic_string_view<_CharT> __s) noexcept
   : _M_str(__s) { }
 
@@ -173,6 +174,7 @@ namespace __format
basic_format_string(const _Tp& __s);
 
   [[__gnu__::__always_inline__]]
+  _GLIBCXX26_CONSTEXPR
   basic_format_string(__format::_Runtime_format_string<_CharT> __s) 
noexcept
   : _M_str(__s._M_str)
   { }
@@ -197,13 +199,13 @@ namespace __format
 
 #if __cpp_lib_format >= 202311L // >= C++26
   [[__gnu__::__always_inline__]]
-  inline __format::_Runtime_format_string
+  inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string
   runtime_format(string_view __fmt) noexcept
   { return __fmt; }
 
 #ifdef _GLIBCXX_USE_WCHAR_T
   [[__gnu__::__always_inline__]]
-  inline __format::_Runtime_format_string
+  inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string
   runtime_format(wstring_view __fmt) noexcept
   { return __fmt; }
 #endif
@@ -238,7 +240,7 @@ namespace __format
 
   /// @cond undocumented
   [[noreturn]]
-  inline void
+  inline _GLIBCXX26_CONSTEXPR void
   __throw_format_error(const char* __what)
   { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
 
@@ -249,27 +251,27 @@ namespace __format
   // XXX use named functions for each constexpr error?
 
   [[noreturn]]
-  inline void
+  inline 

[PATCH] libstdc++: implement constexpr std::format

2026-02-25 Thread Ivan Lazaric
This patch partially implements constexpr formatting from P3391R2,
and defines the feature test macro__cpp_lib_constexpr_format to 202511L,
provided only in .

This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.

Add `__format::__{toupper,memcpy}` functions that work in constexpr.

Due to constexpr limitations, previous implementation of
`_Arg_value::_M_set` via `_S_get` wouldn't work.
Instead of adding a `_S_set` function duplicating most of the
`_S_get` logic, generalize `_S_get` to `_S_get_set` by
folding over assignment, update `_M_set` to go through it.

Avoid using `_Ptr_sink` in constexpr, in `__do_vformat_to`
and `formatted_size`.

Update some formatting tests to test constexpr as well.

This patch is missing:
* wide constexpr formatting
* more constexpr tests

libstdc++-v3/ChangeLog:

* include/bits/version.def (constexpr_format): Define.
* include/bits/version.h: Regenerate.
* include/std/format:
(__format::__toupper, __format::memcpy): Define.
(_Arg_value::_S_get): Generalize to _S_get_set.
(__format::_Counting_constexpr_sink): Define.
(__format::__do_vformat_to, formatted_size):
Avoid using _Ptr_sink in constexpr.
* testsuite/std/format/functions/format.cc: Constexpr testing.
* testsuite/std/format/functions/format_to.cc: Constexpr testing.
* testsuite/std/format/ranges/format_kind.cc: Constexpr testing.
* testsuite/std/format/ranges/formatter.cc: Constexpr testing.
* testsuite/std/format/ranges/sequence.cc: Constexpr testing.
* testsuite/std/format/string.cc: Constexpr testing.
* testsuite/std/format/tuple.cc: Constexpr testing.

Signed-off-by: Ivan Lazaric 
---
This patch is based on top of the 2 following not-yet-merged patches:
libstdc++: Store basic_format_arg::handle in __format::_Arg_value
libstdc++: Introduce __format::_Ptr_sink for contingous iterators



 libstdc++-v3/include/bits/version.def |  10 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/format   | 367 ++
 .../testsuite/std/format/functions/format.cc  | 191 +
 .../std/format/functions/format_to.cc |  58 ++-
 .../std/format/ranges/format_kind.cc  |  11 +-
 .../testsuite/std/format/ranges/formatter.cc  |  40 +-
 .../testsuite/std/format/ranges/sequence.cc   |  73 +++-
 libstdc++-v3/testsuite/std/format/string.cc   | 222 ++-
 libstdc++-v3/testsuite/std/format/tuple.cc|  72 +++-
 10 files changed, 742 insertions(+), 312 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index c7709ba3a07..827498732c6 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1330,6 +1330,16 @@ ftms = {
   };
 };
 
+ftms = {
+  name = constexpr_format;
+  // 202511 P3391R2 constexpr std::format
+  values = {
+v = 202511;
+cxxmin = 26;
+hosted = yes;
+  };
+};
+
 ftms = {
   name = format_uchar;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index c72cda506f1..4911b741bb1 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1476,6 +1476,16 @@
 #endif /* !defined(__cpp_lib_format) */
 #undef __glibcxx_want_format
 
+#if !defined(__cpp_lib_constexpr_format)
+# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
+#  define __glibcxx_constexpr_format 202511L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_format)
+#   define __cpp_lib_constexpr_format 202511L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_constexpr_format) */
+#undef __glibcxx_want_constexpr_format
+
 #if !defined(__cpp_lib_format_uchar)
 # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
 #  define __glibcxx_format_uchar 202311L
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 245ea964675..1ecfabb2590 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -39,6 +39,7 @@
 #define __glibcxx_want_format_ranges
 #define __glibcxx_want_format_uchar
 #define __glibcxx_want_constexpr_exceptions
+#define __glibcxx_want_constexpr_format
 #include 
 
 #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
@@ -98,6 +99,34 @@ namespace __format
 #define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen(S, L##S)
 #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
 
+  [[__gnu__::__always_inline__]]
+  constexpr char
+  __toupper(char __c)
+  {
+if consteval {
+  if (__c < 'a' || __c > 'z') return __c;
+  return __c - 'a' + 'A';
+} else {
+#if __has_builtin(__builtin_toupper)
+  return __builtin_toupper(__c);
+#else
+  return std::toupper(__c);
+#endif
+}
+  }
+
+  [[__gnu__::__always_inline__]]
+  constexpr void
+  __memcpy(char* __dest, const char* __src, size_t __n)
+  {
+if consteval {
+  for (size_t __i = 0; __i < __n; ++__i)
+   __dest[__i] = __src[_