[PATCH] libstdc++: Export explicit instantiations of __format::__do_vformat_to.

Jonathan Wakely jwakely.gcc@gmail.com
Fri Apr 3 15:20:53 GMT 2026


On Fri, 3 Apr 2026, 12:50 Tomasz Kaminski, <tkaminsk@redhat.com> wrote:

>
>
> On Fri, Apr 3, 2026 at 1:48 PM Tomasz Kamiński <tkaminsk@redhat.com>
> wrote:
>
>> This patch exports instantiations of __format::__do_vformat_to
>> for _Sink_iter and char/wchar_t. As every format function is
>> implementing as delegating the one of these overloads, this
>> significantly reduces the compliation time.
>>
>> Instantiating __format::__do_vformat_to triggers specializations
>> of formatters for types stored in handle direclty (arithmetic
>> types, strings), however we do not export any of their symbols.
>> This keeps the interface boundary minimal. This file should
>> be recompiled in later mode, when it is called stable.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * config/abi/pre/gnu.ver (GLIBCXX_3.4): Exclude exports
>>         of std::basic_fo* (matching basic_format_context).
>>         (GLIBCXX_3.4.35): Export __format::__do_vformat_to
>>         specializations for _Sink_iter and char/wchar_t.
>>         * include/std/format: (__format::__do_vformat_to):
>>         Remove inline and declare extern instantiation
>>         of __format::__do_vformat_to _Sink_iter and char/wchar_t.
>>         * src/c++20/Makefile.am: Add format-inst.cc.
>>         * src/c++20/Makefile.in: Regenerate.
>>         * src/c++20/format-inst.cc: New file defining explicit
>>         instantiation.
>> ---
>> From simple test on files from testsuite/std/format/functions/, the
>> results looks very promising:
>>
>>                 Before  After
>> format.cc       24.203s 10.846s
>> format_to.cc    18.475s 2.844s
>> format_to_n.cc  18.677s 3.074s
>> vformat_to.cc   17.281s 2.246s
>>
>> However, I am a bit concerned if the approach works, as
>> libstdc++.so will always contains weak simbol for __do_vformat_to
>> for _Sink_iter<char>, that supports only C++20 specifiers.
>> Should we instead compile the format-inst in latest mode, and
>> always provide extern defintion?
>> Note that the same problem will also be present for the print function,
>> but I haven not realized it then.
>>
> The scenarios like that are not only teoreticall, debug support (?) for
> string and char was recently added.
>

Yes, I think we should instantiate the latest definition.

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.




>> I plan to do similar change for __formatter_chrono<char>::_M_format
>> functions (entry point).
>>
>>
>>  libstdc++-v3/config/abi/pre/gnu.ver   |  8 ++++-
>>  libstdc++-v3/include/std/format       | 13 +++++++-
>>  libstdc++-v3/src/c++20/Makefile.am    |  3 +-
>>  libstdc++-v3/src/c++20/Makefile.in    |  6 ++--
>>  libstdc++-v3/src/c++20/format-inst.cc | 46 +++++++++++++++++++++++++++
>>  5 files changed, 71 insertions(+), 5 deletions(-)
>>  create mode 100644 libstdc++-v3/src/c++20/format-inst.cc
>>
>> diff --git a/libstdc++-v3/config/abi/pre/gnu.ver
>> b/libstdc++-v3/config/abi/pre/gnu.ver
>> index fb968e122d8..2b391584c94 100644
>> --- a/libstdc++-v3/config/abi/pre/gnu.ver
>> +++ b/libstdc++-v3/config/abi/pre/gnu.ver
>> @@ -34,7 +34,9 @@ GLIBCXX_3.4 {
>>        std::basic_[a-e]*;
>>        std::basic_f[a-h]*;
>>  #     std::basic_filebuf;
>> -      std::basic_f[j-r]*;
>> +      std::basic_f[j-n]*;
>> +#     std::basic_format_context;
>> +      std::basic_f[p-r]*;
>>  #     std::basic_fstream;
>>        std::basic_f[t-z]*;
>>        std::basic_[g-h]*;
>> @@ -2587,6 +2589,10 @@ GLIBCXX_3.4.35 {
>>      _ZNSt12__cow_stringaSEOS_;
>>      _ZNKSt12__cow_string5c_strEv;
>>
>> +    # __format::__do_vformat_to(_Sink_iter<char>, string_view, const
>> format_args&, const locale*);
>> +    # __format::__do_vformat_to(_Sink_iter<wchar_t>, wstring_view, const
>> wformat_args&, const locale*);
>> +
>> _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;
>> +
>>  #if defined (_WIN32) && !defined (__CYGWIN__)
>>      _ZSt19__get_once_callablev;
>>      _ZSt15__get_once_callv;
>> diff --git a/libstdc++-v3/include/std/format
>> b/libstdc++-v3/include/std/format
>> index eca5bd213aa..2a8229a2eb5 100644
>> --- a/libstdc++-v3/include/std/format
>> +++ b/libstdc++-v3/include/std/format
>> @@ -5220,7 +5220,7 @@ namespace __format
>>      };
>>
>>    template<typename _Out, typename _CharT, typename _Context>
>> -    inline _Out
>> +    _Out
>>      __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>>                     const basic_format_args<_Context>& __args,
>>                     const locale* __loc)
>> @@ -5310,6 +5310,17 @@ namespace __format
>>         }
>>      }
>>
>> +#if __cplusplus <= 202002L && _GLIBCXX_EXTERN_TEMPLATE > 0
>> +    extern template _Sink_iter<char>
>> +      __do_vformat_to(_Sink_iter<char>, string_view,
>> +                     const format_args&, const locale*);
>> +# ifdef _GLIBCXX_USE_WCHAR_T
>> +    extern template _Sink_iter<wchar_t>
>> +      __do_vformat_to(_Sink_iter<wchar_t>, wstring_view,
>> +                     const wformat_args&, const locale*);
>> +# endif
>> +#endif
>> +
>>    template<typename _Out, typename _CharT>
>>      format_to_n_result<_Out>
>>      __do_vformat_to_n(_Out __out, iter_difference_t<_Out> __n,
>> diff --git a/libstdc++-v3/src/c++20/Makefile.am
>> b/libstdc++-v3/src/c++20/Makefile.am
>> index 0061678dc0f..7744fa43a63 100644
>> --- a/libstdc++-v3/src/c++20/Makefile.am
>> +++ b/libstdc++-v3/src/c++20/Makefile.am
>> @@ -30,7 +30,8 @@ headers =
>>  if ENABLE_EXTERN_TEMPLATE
>>  # XTEMPLATE_FLAGS = -fno-implicit-templates
>>  inst_sources = \
>> -       sstream-inst.cc
>> +       sstream-inst.cc \
>> +       format-inst.cc
>>  else
>>  # XTEMPLATE_FLAGS =
>>  inst_sources =
>> diff --git a/libstdc++-v3/src/c++20/Makefile.in
>> b/libstdc++-v3/src/c++20/Makefile.in
>> index f481ad08edb..566d7292021 100644
>> --- a/libstdc++-v3/src/c++20/Makefile.in
>> +++ b/libstdc++-v3/src/c++20/Makefile.in
>> @@ -124,7 +124,8 @@ CONFIG_CLEAN_VPATH_FILES =
>>  LTLIBRARIES = $(noinst_LTLIBRARIES)
>>  libc__20convenience_la_LIBADD =
>>  am__objects_1 = tzdb.lo format.lo atomic.lo clock.lo syncbuf.lo
>> -@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo
>> +@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo \
>> +@ENABLE_EXTERN_TEMPLATE_TRUE@  format-inst.lo
>>  @GLIBCXX_HOSTED_TRUE@am_libc__20convenience_la_OBJECTS =  \
>>  @GLIBCXX_HOSTED_TRUE@  $(am__objects_1) $(am__objects_2)
>>  libc__20convenience_la_OBJECTS = $(am_libc__20convenience_la_OBJECTS)
>> @@ -433,7 +434,8 @@ headers =
>>
>>  # XTEMPLATE_FLAGS = -fno-implicit-templates
>>  @ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = \
>> -@ENABLE_EXTERN_TEMPLATE_TRUE@  sstream-inst.cc
>> +@ENABLE_EXTERN_TEMPLATE_TRUE@  sstream-inst.cc \
>> +@ENABLE_EXTERN_TEMPLATE_TRUE@  format-inst.cc
>>
>>  sources = tzdb.cc format.cc atomic.cc clock.cc syncbuf.cc
>>  @GLIBCXX_HOSTED_FALSE@libc__20convenience_la_SOURCES =
>> diff --git a/libstdc++-v3/src/c++20/format-inst.cc
>> b/libstdc++-v3/src/c++20/format-inst.cc
>> new file mode 100644
>> index 00000000000..1904de35f7b
>> --- /dev/null
>> +++ b/libstdc++-v3/src/c++20/format-inst.cc
>> @@ -0,0 +1,46 @@
>> +// Definitions for <chrono> formatting -*- C++ -*-
>> +
>> +// Copyright The GNU Toolchain Authors.
>> +//
>> +// This file is part of the GNU ISO C++ Library.  This library is free
>> +// software; you can redistribute it and/or modify it under the
>> +// terms of the GNU General Public License as published by the
>> +// Free Software Foundation; either version 3, or (at your option)
>> +// any later version.
>> +
>> +// This library is distributed in the hope that it will be useful,
>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +// GNU General Public License for more details.
>> +
>> +// Under Section 7 of GPL version 3, you are granted additional
>> +// permissions described in the GCC Runtime Library Exception, version
>> +// 3.1, as published by the Free Software Foundation.
>> +
>> +// You should have received a copy of the GNU General Public License and
>> +// a copy of the GCC Runtime Library Exception along with this program;
>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>> +// <http://www.gnu.org/licenses/>.
>> +
>> +#include <format>
>> +#include <chrono>
>> +
>> +namespace std
>> +{
>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>> +namespace __format
>> +{
>> +
>> + template _Sink_iter<char>
>> +   __do_vformat_to(_Sink_iter<char>, string_view,
>> +                  const format_args&, const locale*);
>> +
>> +# ifdef _GLIBCXX_USE_WCHAR_T
>> + template _Sink_iter<wchar_t>
>> +   __do_vformat_to(_Sink_iter<wchar_t>, wstring_view,
>> +                  const wformat_args&, const locale*);
>> +# endif
>> +
>> +} // namespace __format
>> +_GLIBCXX_END_NAMESPACE_VERSION
>> +} // namespace std
>> --
>> 2.53.0
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260403/859e6967/attachment.htm>


More information about the Libstdc++ mailing list