<div dir="auto"><div><br><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Fri, 3 Apr 2026, 12:50 Tomasz Kaminski, <<a href="mailto:tkaminsk@redhat.com">tkaminsk@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 3, 2026 at 1:48 PM Tomasz Kamiński <<a href="mailto:tkaminsk@redhat.com" target="_blank" rel="noreferrer">tkaminsk@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This patch exports instantiations of __format::__do_vformat_to<br>
for _Sink_iter and char/wchar_t. As every format function is<br>
implementing as delegating the one of these overloads, this<br>
significantly reduces the compliation time.<br>
<br>
Instantiating __format::__do_vformat_to triggers specializations<br>
of formatters for types stored in handle direclty (arithmetic<br>
types, strings), however we do not export any of their symbols.<br>
This keeps the interface boundary minimal. This file should<br>
be recompiled in later mode, when it is called stable.<br>
<br>
libstdc++-v3/ChangeLog:<br>
<br>
* config/abi/pre/gnu.ver (GLIBCXX_3.4): Exclude exports<br>
of std::basic_fo* (matching basic_format_context).<br>
(GLIBCXX_3.4.35): Export __format::__do_vformat_to<br>
specializations for _Sink_iter and char/wchar_t.<br>
* include/std/format: (__format::__do_vformat_to):<br>
Remove inline and declare extern instantiation<br>
of __format::__do_vformat_to _Sink_iter and char/wchar_t.<br>
* src/c++20/Makefile.am: Add format-inst.cc.<br>
* src/c++20/Makefile.in: Regenerate.<br>
* src/c++20/format-inst.cc: New file defining explicit<br>
instantiation.<br>
---<br>
>From simple test on files from testsuite/std/format/functions/, the<br>
results looks very promising:<br>
<br>
Before After<br>
format.cc 24.203s 10.846s<br>
format_to.cc 18.475s 2.844s<br>
format_to_n.cc 18.677s 3.074s <br>
vformat_to.cc 17.281s 2.246s<br>
<br>
However, I am a bit concerned if the approach works, as<br>
libstdc++.so will always contains weak simbol for __do_vformat_to<br>
for _Sink_iter<char>, that supports only C++20 specifiers.<br>
Should we instead compile the format-inst in latest mode, and<br>
always provide extern defintion?<br>
Note that the same problem will also be present for the print function,<br>
but I haven not realized it then.<br></blockquote><div>The scenarios like that are not only teoreticall, debug support (?) for</div><div>string and char was recently added. </div></div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Yes, I think we should instantiate the latest definition. </div><div dir="auto"><br></div><div dir="auto">Before C++26 there's no way to use those new format specifiers anyway, because the format string is always parsed as a consteval format_string and so only C++20 or C++23 formats will be recognized.</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote gmail_quote_container"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
I plan to do similar change for __formatter_chrono<char>::_M_format<br>
functions (entry point).<br>
<br>
<br>
libstdc++-v3/config/abi/pre/gnu.ver | 8 ++++-<br>
libstdc++-v3/include/std/format | 13 +++++++-<br>
libstdc++-v3/src/c++20/Makefile.am | 3 +-<br>
libstdc++-v3/src/c++20/Makefile.in | 6 ++--<br>
libstdc++-v3/src/c++20/format-inst.cc | 46 +++++++++++++++++++++++++++<br>
5 files changed, 71 insertions(+), 5 deletions(-)<br>
create mode 100644 libstdc++-v3/src/c++20/format-inst.cc<br>
<br>
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver<br>
index fb968e122d8..2b391584c94 100644<br>
--- a/libstdc++-v3/config/abi/pre/gnu.ver<br>
+++ b/libstdc++-v3/config/abi/pre/gnu.ver<br>
@@ -34,7 +34,9 @@ GLIBCXX_3.4 {<br>
std::basic_[a-e]*;<br>
std::basic_f[a-h]*;<br>
# std::basic_filebuf;<br>
- std::basic_f[j-r]*;<br>
+ std::basic_f[j-n]*;<br>
+# std::basic_format_context;<br>
+ std::basic_f[p-r]*;<br>
# std::basic_fstream;<br>
std::basic_f[t-z]*;<br>
std::basic_[g-h]*;<br>
@@ -2587,6 +2589,10 @@ GLIBCXX_3.4.35 {<br>
_ZNSt12__cow_stringaSEOS_;<br>
_ZNKSt12__cow_string5c_strEv;<br>
<br>
+ # __format::__do_vformat_to(_Sink_iter<char>, string_view, const format_args&, const locale*);<br>
+ # __format::__do_vformat_to(_Sink_iter<wchar_t>, wstring_view, const wformat_args&, const locale*);<br>
+ _ZNSt8__format15__do_vformat_toINS_10_Sink_iterI[wc]EE[wc]St20basic_format_contextIS2_[wc]EEET_S5_St17basic_string_viewIT0_St11char_traitsIS7_EERKSt17basic_format_argsIT1_EPKSt6locale;<br>
+<br>
#if defined (_WIN32) && !defined (__CYGWIN__)<br>
_ZSt19__get_once_callablev;<br>
_ZSt15__get_once_callv;<br>
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format<br>
index eca5bd213aa..2a8229a2eb5 100644<br>
--- a/libstdc++-v3/include/std/format<br>
+++ b/libstdc++-v3/include/std/format<br>
@@ -5220,7 +5220,7 @@ namespace __format<br>
};<br>
<br>
template<typename _Out, typename _CharT, typename _Context><br>
- inline _Out<br>
+ _Out<br>
__do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,<br>
const basic_format_args<_Context>& __args,<br>
const locale* __loc)<br>
@@ -5310,6 +5310,17 @@ namespace __format<br>
}<br>
}<br>
<br>
+#if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0<br>
+ extern template _Sink_iter<char><br>
+ __do_vformat_to(_Sink_iter<char>, string_view,<br>
+ const format_args&, const locale*);<br>
+# ifdef _GLIBCXX_USE_WCHAR_T<br>
+ extern template _Sink_iter<wchar_t><br>
+ __do_vformat_to(_Sink_iter<wchar_t>, wstring_view,<br>
+ const wformat_args&, const locale*);<br>
+# endif<br>
+#endif<br>
+<br>
template<typename _Out, typename _CharT><br>
format_to_n_result<_Out><br>
__do_vformat_to_n(_Out __out, iter_difference_t<_Out> __n,<br>
diff --git a/libstdc++-v3/src/c++20/Makefile.am b/libstdc++-v3/src/c++20/Makefile.am<br>
index 0061678dc0f..7744fa43a63 100644<br>
--- a/libstdc++-v3/src/c++20/Makefile.am<br>
+++ b/libstdc++-v3/src/c++20/Makefile.am<br>
@@ -30,7 +30,8 @@ headers =<br>
if ENABLE_EXTERN_TEMPLATE<br>
# XTEMPLATE_FLAGS = -fno-implicit-templates<br>
inst_sources = \<br>
- sstream-inst.cc<br>
+ sstream-inst.cc \<br>
+ format-inst.cc<br>
else<br>
# XTEMPLATE_FLAGS =<br>
inst_sources =<br>
diff --git a/libstdc++-v3/src/c++20/Makefile.in b/libstdc++-v3/src/c++20/Makefile.in<br>
index f481ad08edb..566d7292021 100644<br>
--- a/libstdc++-v3/src/c++20/Makefile.in<br>
+++ b/libstdc++-v3/src/c++20/Makefile.in<br>
@@ -124,7 +124,8 @@ CONFIG_CLEAN_VPATH_FILES =<br>
LTLIBRARIES = $(noinst_LTLIBRARIES)<br>
libc__20convenience_la_LIBADD =<br>
am__objects_1 = tzdb.lo format.lo atomic.lo clock.lo syncbuf.lo<br>
-@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo<br>
+@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo \<br>
+@ENABLE_EXTERN_TEMPLATE_TRUE@ format-inst.lo<br>
@GLIBCXX_HOSTED_TRUE@am_libc__20convenience_la_OBJECTS = \<br>
@GLIBCXX_HOSTED_TRUE@ $(am__objects_1) $(am__objects_2)<br>
libc__20convenience_la_OBJECTS = $(am_libc__20convenience_la_OBJECTS)<br>
@@ -433,7 +434,8 @@ headers =<br>
<br>
# XTEMPLATE_FLAGS = -fno-implicit-templates<br>
@ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = \<br>
-@ENABLE_EXTERN_TEMPLATE_TRUE@ sstream-inst.cc<br>
+@ENABLE_EXTERN_TEMPLATE_TRUE@ sstream-inst.cc \<br>
+@ENABLE_EXTERN_TEMPLATE_TRUE@ format-inst.cc<br>
<br>
sources = tzdb.cc format.cc atomic.cc clock.cc syncbuf.cc<br>
@GLIBCXX_HOSTED_FALSE@libc__20convenience_la_SOURCES = <br>
diff --git a/libstdc++-v3/src/c++20/format-inst.cc b/libstdc++-v3/src/c++20/format-inst.cc<br>
new file mode 100644<br>
index 00000000000..1904de35f7b<br>
--- /dev/null<br>
+++ b/libstdc++-v3/src/c++20/format-inst.cc<br>
@@ -0,0 +1,46 @@<br>
+// Definitions for <chrono> formatting -*- C++ -*-<br>
+<br>
+// Copyright The GNU Toolchain Authors.<br>
+//<br>
+// This file is part of the GNU ISO C++ Library. This library is free<br>
+// software; you can redistribute it and/or modify it under the<br>
+// terms of the GNU General Public License as published by the<br>
+// Free Software Foundation; either version 3, or (at your option)<br>
+// any later version.<br>
+<br>
+// This library is distributed in the hope that it will be useful,<br>
+// but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
+// GNU General Public License for more details.<br>
+<br>
+// Under Section 7 of GPL version 3, you are granted additional<br>
+// permissions described in the GCC Runtime Library Exception, version<br>
+// 3.1, as published by the Free Software Foundation.<br>
+<br>
+// You should have received a copy of the GNU General Public License and<br>
+// a copy of the GCC Runtime Library Exception along with this program;<br>
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see<br>
+// <<a href="http://www.gnu.org/licenses/" rel="noreferrer noreferrer" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
+<br>
+#include <format><br>
+#include <chrono><br>
+<br>
+namespace std<br>
+{<br>
+_GLIBCXX_BEGIN_NAMESPACE_VERSION<br>
+namespace __format<br>
+{<br>
+<br>
+ template _Sink_iter<char><br>
+ __do_vformat_to(_Sink_iter<char>, string_view,<br>
+ const format_args&, const locale*);<br>
+<br>
+# ifdef _GLIBCXX_USE_WCHAR_T<br>
+ template _Sink_iter<wchar_t><br>
+ __do_vformat_to(_Sink_iter<wchar_t>, wstring_view,<br>
+ const wformat_args&, const locale*);<br>
+# endif<br>
+<br>
+} // namespace __format<br>
+_GLIBCXX_END_NAMESPACE_VERSION<br>
+} // namespace std<br>
-- <br>
2.53.0<br>
<br>
</blockquote></div></div>
</blockquote></div></div></div>