[PATCH] libstdc++: Expose translation related context in format_contexts.

Tomasz Kaminski tkaminsk@redhat.com
Thu Apr 16 09:55:43 GMT 2026


On Thu, Apr 9, 2026 at 10:11 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:

>
>
> On Tue, Apr 7, 2026 at 5:47 PM Jonathan Wakely <jwakely.gcc@gmail.com>
> wrote:
>
>>
>>
>> On Tue, 7 Apr 2026, 15:09 Tomasz Kaminski, <tkaminsk@redhat.com> wrote:
>>
>>>
>>>
>>> On Tue, Apr 7, 2026 at 3:54 PM Jonathan Wakely <jwakely.gcc@gmail.com>
>>> wrote:
>>>
>>>>
>>>>
>>>> On Tue, 7 Apr 2026, 14:30 Tomasz Kaminski, <tkaminsk@redhat.com> wrote:
>>>>
>>>>>
>>>>>
>>>>> On Tue, Apr 7, 2026 at 3:00 PM Jonathan Wakely <jwakely.gcc@gmail.com>
>>>>> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On Tue, 7 Apr 2026, 09:15 Tomasz Kamiński, <tkaminsk@redhat.com>
>>>>>> wrote:
>>>>>>
>>>>>>> This patch adds a _M_api member to basic_format_context and
>>>>>>> basic_format_parse_context, that represents the information about
>>>>>>> the TU in which the call was compiled:
>>>>>>> * _M_ver represents the C++ standard in which TU was compiled,
>>>>>>> * _M_literal_unicode is true when TU was compiled with Unicode
>>>>>>>   literal encoding,
>>>>>>> * _M_liter_enc is reserved for storing text_encoding::id value
>>>>>>>   for literal encoding, currently set to zero.
>>>>>>> This values are then populated by __current_api<_CharT>() functions.
>>>>>>>
>>>>>>> This would allow the formatter instantiations compiled in different
>>>>>>> TU (for example as part of libstdc++.so) to properly handle:
>>>>>>> * multi-byte fill-characters used as fill in format-spec, that
>>>>>>>   are supported only if literal encoding is Unicode,
>>>>>>> * '?' as format flags for string and characters, that is only
>>>>>>>   supported since C++23,
>>>>>>> * escaping of the string parameters, that depends on the literal
>>>>>>>   encoding.
>>>>>>>
>>>>>>> The further aid the above, a new __do_vformat_to overload is
>>>>>>> extracted.
>>>>>>> This overload format_context& that encodes the TU-specific
>>>>>>> properties,
>>>>>>> and can be exported in from libstdc++.
>>>>>>>
>>>>>>> This patch on purpose does not modify the formatters code, and only
>>>>>>> adds new members, as adding them later would be ABI break.
>>>>>>>
>>>>>>> libstdc++-v3/ChangeLog:
>>>>>>>
>>>>>>>         * include/std/format (__format::_Api_ctx,
>>>>>>> __format::__current_api):
>>>>>>>         Define.
>>>>>>>         (basic_format_parse_context::_M_api): Define.
>>>>>>>         (basic_format_parse_context::basic_format_parse_context):
>>>>>>>         Provide (basic_string_view, size_t) constructor only in
>>>>>>> C++20.
>>>>>>>         Define new internal private cosntructor accepting _Api_ctx.
>>>>>>>         (basic_format_context::_M_api): Define.
>>>>>>>         (basic_format_context::basic_format_context): Add additional
>>>>>>>         _Api_ctx parameter.
>>>>>>>         (_Scanner::_Scanner): Add additional _Api_ctx parameter,
>>>>>>>         and forward it to basic_format_parse_context.
>>>>>>>         (_Formatting_scanner::_Formatting_scanner): Propagate
>>>>>>>         _M_api from basic_format_context.
>>>>>>>         (_Checking_scanner::_Checking_scanner): Use
>>>>>>> __format::__current_api()
>>>>>>>         to initialize API.
>>>>>>>         (__format::__do_vformat_to): Extract overload accepting
>>>>>>>         basic_format_context.
>>>>>>> ---
>>>>>>> I have realized that exporting the vformat specializations correclty
>>>>>>> requires
>>>>>>> much bigger code changes, than I am comfortable making this late in
>>>>>>> the stage-4,
>>>>>>> as we will need to make the code independed on TU specific
>>>>>>> properties (like
>>>>>>> encodinds). This patch instead adds a context members to
>>>>>>> basic_format_context
>>>>>>> and basic_format_parse_context that would allow doing so in the
>>>>>>> future.
>>>>>>>
>>>>>>
>>>>>> An alternative would be to have an inline dispatching function that
>>>>>> decides whether the current TU matches what's in the library (where that
>>>>>> will be the common case) and only uses the explicit instantiations of it
>>>>>> matches.
>>>>>>
>>>>> Seems reasonable for unicode encoding, but does not solve multiple
>>>>> standard.
>>>>>
>>>>>>
>>>>>> I'm not sure this is really a problem I care about solving. If you
>>>>>> try to mix incompatible literal encodings in one program you shouldn't
>>>>>> expect sensible results for code that is sensitive to the literal encoding.
>>>>>>
>>>>>> When mixing C++20 and C++23, the C++20 TUs should use the explicit
>>>>>> instantiation which is right for C++20, and C++23 TUs will use an implicit
>>>>>> instantiation of the C++23 definition.
>>>>>>
>>>>> This works only on surface level, C++20 will use __vformat_impl_20 and
>>>>> C++23 will use __vformat_impl_23, defined in format-inst-20, format-inst-23
>>>>> source files.
>>>>>
>>>>
>>>> Once we stabilise C++23 I think we should only instantiate the format
>>>> functions for C++23. Will anybody really care if they use a dynamic format
>>>> string in C++20 code and don't get an exception for using a C++23 format
>>>> specifier?
>>>>
>>> Yes, the fact that the format specifier string is accepted by `vformat`
>>> but rejected by `format` seems very surprising to me, but if we accepted
>>> that we have a much simpler problem to solve. If we plan to accept all
>>> C++23 specifiers for basic types as extension in C++20 mode, once
>>> it will be stabilized, then that would sound much more intuitive for me.
>>>
>>>>
>>>> Both of these files will instantiate `__formatter_str` under the same
>>>>> name. When they are combined into `libstdc++.so`, linker one, and one
>>>>> standard
>>>>> will get incorrect behavior for one of the standards.
>>>>>
>>>>
>>>> Fine, the older standard could get the "wrong"  behaviour (where wrong
>>>> just means supporting C++23 features when called from C++20 TUs).
>>>>
>>> I considered that unacceptable, and we even have a test cases checking
>>> if that is the case. The failures for these tests were the reason
>>> I started exploring alternatives.
>>>
>>>>
>>>> To avoid this problem we will need to ABI tag each used formatter in
>>>>> some manner and apply that
>>>>> tag virally to any formatter referenced from these functions.
>>>>>
>>>>>
>>>>>>
>>>>>> Is there really a problem?
>>>>>>
>>>>>> If we can capture the API level without adding any overhead, I
>>>>>> suppose that's acceptable.
>>>>>>
>>>>>> If we store the text encoding, what are we going to do with it? Use
>>>>>> iconv to convert the fill character on the fly? To what output encoding?
>>>>>>
>>>>> This if for future, if we want to handle string escaping for
>>>>> non-unicode encoding better than giving them equivalent behavior than ASCII.
>>>>> We can add any additional fields to basic_format_parse_context and
>>>>> basic_format_context in the future; this is why I am reserving space for it.
>>>>>
>>>>> // Also could you take a look at:
>>>>> https://gcc.gnu.org/pipermail/libstdc++/2026-April/066030.html
>>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Tested all *format* test on x86_64-linux. OK for trunk when all test
>>>>>>> passes?
>>>>>>>
>>>>>>>  libstdc++-v3/include/std/format | 209
>>>>>>> ++++++++++++++++++++------------
>>>>>>>  1 file changed, 133 insertions(+), 76 deletions(-)
>>>>>>>
>>>>>>> diff --git a/libstdc++-v3/include/std/format
>>>>>>> b/libstdc++-v3/include/std/format
>>>>>>> index eca5bd213aa..97d1ecb3ed6 100644
>>>>>>> --- a/libstdc++-v3/include/std/format
>>>>>>> +++ b/libstdc++-v3/include/std/format
>>>>>>> @@ -140,6 +140,37 @@ namespace __format
>>>>>>>        template<typename, typename...> friend struct
>>>>>>> std::basic_format_string;
>>>>>>>      };
>>>>>>>
>>>>>>> +  // Exposed via basic_format_parse_context, defines the TU
>>>>>>> specific information
>>>>>>> +  // like encoding and standard version.
>>>>>>> +  struct _Api_ctx
>>>>>>> +  {
>>>>>>> +    enum class _Version : unsigned char
>>>>>>> +    { _Api_2020, _Api_2023, _Api_2026 };
>>>>>>> +
>>>>>>> +    _Version _M_ver;
>>>>>>> +    unsigned _M_unused : 23;
>>>>>>> +    unsigned _M_literal_unicode : 1;
>>>>>>> +    __INT_LEAST32_TYPE__ _M_literal_enc;
>>>>>>> +  };
>>>>>>> +  using enum _Api_ctx::_Version;
>>>>>>> +
>>>>>>> +  template<typename _CharT>
>>>>>>> +    constexpr _Api_ctx
>>>>>>> +    __current_api()
>>>>>>>
>>>>>>
>>>>>> Should this be always inline?
>>>>>>
>>>>>> +    {
>>>>>>> +      _Api_ctx __api{};
>>>>>>> +#if __cpluplus > 202302L
>>>>>>> +      __api._M_ver = _Api_2026;
>>>>>>> +#elif __cpluplus > 202002L
>>>>>>> +      __api._M_ver = _Api_2023;
>>>>>>> +#else
>>>>>>> +      __api._M_ver = _Api_2020;
>>>>>>> +#endif
>>>>>>> +      __api._M_literal_unicode
>>>>>>> +       = __unicode::__literal_encoding_is_unicode<_CharT>();
>>>>>>> +      return __api;
>>>>>>> +    }
>>>>>>> +
>>>>>>>  } // namespace __format
>>>>>>>  /// @endcond
>>>>>>>
>>>>>>> @@ -274,7 +305,7 @@ namespace __format
>>>>>>>    { __throw_format_error("format error: failed to parse
>>>>>>> format-spec"); }
>>>>>>>
>>>>>>>    template<typename _CharT> class _Scanner;
>>>>>>> -
>>>>>>> +  template<typename _Out, typename _CharT> class
>>>>>>> _Formatting_scanner;
>>>>>>>  } // namespace __format
>>>>>>>    /// @endcond
>>>>>>>
>>>>>>> @@ -408,23 +439,34 @@ namespace __format
>>>>>>>        // This must not be constexpr.
>>>>>>>        static void __invalid_dynamic_spec(const char*);
>>>>>>>
>>>>>>> -      friend __format::_Scanner<_CharT>;
>>>>>>> -#endif
>>>>>>> -
>>>>>>> +#else
>>>>>>>        // This constructor should only be used by the implementation.
>>>>>>>        constexpr explicit
>>>>>>>        basic_format_parse_context(basic_string_view<_CharT> __fmt,
>>>>>>>                                  size_t __num_args) noexcept
>>>>>>>        : _M_begin(__fmt.begin()), _M_end(__fmt.end()),
>>>>>>> _M_num_args(__num_args)
>>>>>>>        { }
>>>>>>> +#endif
>>>>>>>
>>>>>>>      private:
>>>>>>> +      // This constructor should only be used by the implementation.
>>>>>>> +      constexpr explicit
>>>>>>> +      basic_format_parse_context(__format::_Api_ctx __api,
>>>>>>> +                                basic_string_view<_CharT> __fmt,
>>>>>>> +                                size_t __num_args) noexcept
>>>>>>> +      : _M_api(__api), _M_begin(__fmt.begin()), _M_end(__fmt.end())
>>>>>>> +      , _M_num_args(__num_args)
>>>>>>> +      { }
>>>>>>> +
>>>>>>> +      __format::_Api_ctx _M_api = __format::__current_api<_CharT>();
>>>>>>>
>>>>>>
>>>>>> What guarantees this will be initialized by a call to the right
>>>>>> version?
>>>>>>
>>>>> This is only used by basic_format_parse_context(string) constructor,
>>>>> that is mostly used
>>>>> for user defined-formatters. We may want to define this cosntructors
>>>>> as always inline.
>>>>>
>>>>>>
>>>>>> Doesn't putting this member first add a lot of wasted padding due to
>>>>>> alignment?
>>>>>>
>>>>> I do not think basic_format_parse_context and basic_format_context
>>>>> size is relevant to
>>>>> anybody. But the struct is 64bits, so should not add extra pading.
>>>>>
>>>>
>>>> I don't understand how adding a new byte before the first iterator
>>>> member doesn't introduce sizeof(void*)-1 bytes of padding.
>>>>
>>> _Api_ctx is 8B struct with the literal encoding information. And I
>>> considered having a spare bytes there as a feature, and not
>>> a drawback.
>>>
>>
>> Oh, I thought this was just storing the enum, not the struct. Doh.
>>
>> That explains why I was confused.
>>
>> Thinking more about the questions in the follow up mails....
>>
> We decided to go with simpler model from
https://gcc.gnu.org/pipermail/libstdc++/2026-April/066170.html.

> I think allowing a C++23 format string extension in C++20 mode may be a
> better choice, as it will help us avoid
> all the problems related to linking TU compiled in different standards.
> However, I think we should make that proper
> extension, and make them accepted for contexpr and runtime format.
>
> For sure, we do not want to be in situation, when ? is accepted if you are
> using unicode literal encoding in TU
> (and using exported vformat_to defintion), and not if you are using a
> different encoding. We could add some
> if consteval checks to apply extension only to runtime, but I do not see
> value in that.
>
> In short, I am for policy, let make format strings specifiers accepted as
> extension, once give standard mode
> becomes stable. (On purpose limiting to format-string specifiers, and not
> functions like set_debug_format).
>
>
>>
>>
>>>> Why don't we just give _Indexing a fixed underlying type of unsigned
>>>> char and then put the API version after that?
>>>>
>>>>
>>>>
>>>>
>>>>>>
>>>>>>        iterator _M_begin;
>>>>>>>        iterator _M_end;
>>>>>>>        enum _Indexing { _Unknown, _Manual, _Auto };
>>>>>>>        _Indexing _M_indexing = _Unknown;
>>>>>>>
>>>>>>
>>>>>> We already have padding bytes here (and could guarantee that by
>>>>>> giving a fixed underlying type to _Indexing)
>>>>>>
>>>>>>        size_t _M_next_arg_id = 0;
>>>>>>>        size_t _M_num_args = 0;
>>>>>>> +
>>>>>>> +      friend __format::_Scanner<_CharT>;
>>>>>>>      };
>>>>>>>
>>>>>>>  /// @cond undocumented
>>>>>>> @@ -4927,18 +4969,21 @@ namespace __format
>>>>>>>      {
>>>>>>>        static_assert( output_iterator<_Out, const _CharT&> );
>>>>>>>
>>>>>>> +      __format::_Api_ctx  _M_api;
>>>>>>>        basic_format_args<basic_format_context> _M_args;
>>>>>>>        _Out _M_out;
>>>>>>>        __format::_Optional_locale _M_loc;
>>>>>>>
>>>>>>> -      basic_format_context(basic_format_args<basic_format_context>
>>>>>>> __args,
>>>>>>> +      basic_format_context(__format::_Api_ctx __api,
>>>>>>> +                          basic_format_args<basic_format_context>
>>>>>>> __args,
>>>>>>>                            _Out __out)
>>>>>>> -      : _M_args(__args), _M_out(std::move(__out))
>>>>>>> +      : _M_api(__api), _M_args(__args), _M_out(std::move(__out))
>>>>>>>        { }
>>>>>>>
>>>>>>> -      basic_format_context(basic_format_args<basic_format_context>
>>>>>>> __args,
>>>>>>> +      basic_format_context(__format::_Api_ctx __api,
>>>>>>> +                          basic_format_args<basic_format_context>
>>>>>>> __args,
>>>>>>>                            _Out __out, const std::locale& __loc)
>>>>>>> -      : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
>>>>>>> +      : _M_api(__api), _M_args(__args),
>>>>>>> _M_out(std::move(__out)), _M_loc(__loc)
>>>>>>>        { }
>>>>>>>
>>>>>>>        // _GLIBCXX_RESOLVE_LIB_DEFECTS
>>>>>>> @@ -4954,6 +4999,7 @@ namespace __format
>>>>>>>                                   const locale*);
>>>>>>>
>>>>>>>        friend __format::__formatter_chrono<_CharT>;
>>>>>>> +      friend __format::_Formatting_scanner<_Out, _CharT>;
>>>>>>>
>>>>>>>      public:
>>>>>>>        ~basic_format_context() = default;
>>>>>>> @@ -4998,8 +5044,9 @@ namespace __format
>>>>>>>        } _M_pc;
>>>>>>>
>>>>>>>        constexpr explicit
>>>>>>> -      _Scanner(basic_string_view<_CharT> __str, size_t __nargs =
>>>>>>> (size_t)-1)
>>>>>>> -      : _M_pc(__str, __nargs)
>>>>>>> +      _Scanner(_Api_ctx __api, basic_string_view<_CharT> __str,
>>>>>>> +              size_t __nargs = (size_t)-1)
>>>>>>> +      : _M_pc(__api, __str, __nargs)
>>>>>>>        { }
>>>>>>>
>>>>>>>        constexpr iterator begin() const noexcept { return
>>>>>>> _M_pc.begin(); }
>>>>>>> @@ -5115,7 +5162,7 @@ namespace __format
>>>>>>>      public:
>>>>>>>        _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
>>>>>>>                           basic_string_view<_CharT> __str)
>>>>>>> -      : _Scanner<_CharT>(__str), _M_fc(__fc)
>>>>>>> +      : _Scanner<_CharT>(__fc._M_api, __str), _M_fc(__fc)
>>>>>>>        { }
>>>>>>>
>>>>>>>      private:
>>>>>>> @@ -5176,7 +5223,8 @@ namespace __format
>>>>>>>      public:
>>>>>>>        consteval
>>>>>>>        _Checking_scanner(basic_string_view<_CharT> __str)
>>>>>>> -      : _Scanner<_CharT>(__str, sizeof...(_Args))
>>>>>>> +      : _Scanner<_CharT>(__format::__current_api<_CharT>(),
>>>>>>>
>>>>>>
>>>>>> This is consteval so should use the right version for the current TU.
>>>>>>
>>>>>> +                        __str, sizeof...(_Args))
>>>>>>>        {
>>>>>>>  #if __cpp_lib_format >= 202305L
>>>>>>>         this->_M_pc._M_types = _M_types.data();
>>>>>>> @@ -5219,82 +5267,91 @@ namespace __format
>>>>>>>  #endif
>>>>>>>      };
>>>>>>>
>>>>>>> -  template<typename _Out, typename _CharT, typename _Context>
>>>>>>> -    inline _Out
>>>>>>> -    __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>>>>>>> -                   const basic_format_args<_Context>& __args,
>>>>>>> -                   const locale* __loc)
>>>>>>> +  template<typename _CharT>
>>>>>>> +    _Sink_iter<_CharT>
>>>>>>> +    __do_vformat_to(_Sink_iter<_CharT> __out,
>>>>>>> basic_string_view<_CharT> __fmt,
>>>>>>> +                   __format_context<_CharT>& __ctx)
>>>>>>>      {
>>>>>>> -      if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>>>>>>> -       {
>>>>>>> -         if constexpr (is_same_v<_CharT, char>)
>>>>>>> -           // Fast path for "{}" format strings and simple format
>>>>>>> arg types.
>>>>>>> -           if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] ==
>>>>>>> '}')
>>>>>>> -             {
>>>>>>> -               bool __done = false;
>>>>>>> -               __format::__visit_format_arg([&](auto& __arg) {
>>>>>>> -                 using _Tp = remove_cvref_t<decltype(__arg)>;
>>>>>>> -                 if constexpr (is_same_v<_Tp, bool>)
>>>>>>> +      if constexpr (is_same_v<_CharT, char>)
>>>>>>> +       // Fast path for "{}" format strings and simple format arg
>>>>>>> types.
>>>>>>> +       if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
>>>>>>> +         {
>>>>>>> +           bool __done = false;
>>>>>>> +           __format::__visit_format_arg([&](auto& __arg) {
>>>>>>> +             using _Tp = remove_cvref_t<decltype(__arg)>;
>>>>>>> +             if constexpr (is_same_v<_Tp, bool>)
>>>>>>> +               {
>>>>>>> +                 size_t __len = 4 + !__arg;
>>>>>>> +                 const char* __chars[] = { "false", "true" };
>>>>>>> +                 if (auto __res = __out._M_reserve(__len))
>>>>>>>                     {
>>>>>>> -                     size_t __len = 4 + !__arg;
>>>>>>> -                     const char* __chars[] = { "false", "true" };
>>>>>>> -                     if (auto __res = __out._M_reserve(__len))
>>>>>>> -                       {
>>>>>>> -                         __builtin_memcpy(__res.get(),
>>>>>>> __chars[__arg], __len);
>>>>>>> -                         __res._M_bump(__len);
>>>>>>> -                         __done = true;
>>>>>>> -                       }
>>>>>>> +                     __builtin_memcpy(__res.get(), __chars[__arg],
>>>>>>> __len);
>>>>>>> +                     __res._M_bump(__len);
>>>>>>> +                     __done = true;
>>>>>>>                     }
>>>>>>> -                 else if constexpr (is_same_v<_Tp, char>)
>>>>>>> +               }
>>>>>>> +             else if constexpr (is_same_v<_Tp, char>)
>>>>>>> +               {
>>>>>>> +                 if (auto __res = __out._M_reserve(1))
>>>>>>>                     {
>>>>>>> -                     if (auto __res = __out._M_reserve(1))
>>>>>>> -                       {
>>>>>>> -                         *__res.get() = __arg;
>>>>>>> -                         __res._M_bump(1);
>>>>>>> -                         __done = true;
>>>>>>> -                       }
>>>>>>> +                     *__res.get() = __arg;
>>>>>>> +                     __res._M_bump(1);
>>>>>>> +                     __done = true;
>>>>>>>                     }
>>>>>>> -                 else if constexpr (is_integral_v<_Tp>)
>>>>>>> +               }
>>>>>>> +             else if constexpr (is_integral_v<_Tp>)
>>>>>>> +               {
>>>>>>> +                 make_unsigned_t<_Tp> __uval;
>>>>>>> +                 const bool __neg = __arg < 0;
>>>>>>> +                 if (__neg)
>>>>>>> +                   __uval = make_unsigned_t<_Tp>(~__arg) + 1u;
>>>>>>> +                 else
>>>>>>> +                   __uval = __arg;
>>>>>>> +                 const auto __n = __detail::__to_chars_len(__uval);
>>>>>>> +                 if (auto __res = __out._M_reserve(__n + __neg))
>>>>>>>                     {
>>>>>>> -                     make_unsigned_t<_Tp> __uval;
>>>>>>> -                     const bool __neg = __arg < 0;
>>>>>>> -                     if (__neg)
>>>>>>> -                       __uval = make_unsigned_t<_Tp>(~__arg) + 1u;
>>>>>>> -                     else
>>>>>>> -                       __uval = __arg;
>>>>>>> -                     const auto __n =
>>>>>>> __detail::__to_chars_len(__uval);
>>>>>>> -                     if (auto __res = __out._M_reserve(__n + __neg))
>>>>>>> -                       {
>>>>>>> -                         auto __ptr = __res.get();
>>>>>>> -                         *__ptr = '-';
>>>>>>> -                         __detail::__to_chars_10_impl(__ptr +
>>>>>>> (int)__neg, __n,
>>>>>>> -                                                      __uval);
>>>>>>> -                         __res._M_bump(__n + __neg);
>>>>>>> -                         __done = true;
>>>>>>> -                       }
>>>>>>> +                     auto __ptr = __res.get();
>>>>>>> +                     *__ptr = '-';
>>>>>>> +                     __detail::__to_chars_10_impl(__ptr +
>>>>>>> (int)__neg, __n,
>>>>>>> +                                                  __uval);
>>>>>>> +                     __res._M_bump(__n + __neg);
>>>>>>> +                     __done = true;
>>>>>>>                     }
>>>>>>> -                 else if constexpr (is_convertible_v<_Tp,
>>>>>>> string_view>)
>>>>>>> +               }
>>>>>>> +             else if constexpr (is_convertible_v<_Tp, string_view>)
>>>>>>> +               {
>>>>>>> +                 string_view __sv = __arg;
>>>>>>> +                 if (auto __res = __out._M_reserve(__sv.size()))
>>>>>>>                     {
>>>>>>> -                     string_view __sv = __arg;
>>>>>>> -                     if (auto __res = __out._M_reserve(__sv.size()))
>>>>>>> -                       {
>>>>>>> -                         __builtin_memcpy(__res.get(), __sv.data(),
>>>>>>> __sv.size());
>>>>>>> -                         __res._M_bump(__sv.size());
>>>>>>> -                         __done = true;
>>>>>>> -                       }
>>>>>>> +                     __builtin_memcpy(__res.get(), __sv.data(),
>>>>>>> __sv.size());
>>>>>>> +                     __res._M_bump(__sv.size());
>>>>>>> +                     __done = true;
>>>>>>>                     }
>>>>>>> -               }, __args.get(0));
>>>>>>> +               }
>>>>>>> +           }, __ctx.arg(0));
>>>>>>>
>>>>>>> -               if (__done)
>>>>>>> -                 return __out;
>>>>>>> -             }
>>>>>>> +           if (__done)
>>>>>>> +             return __out;
>>>>>>> +         }
>>>>>>>
>>>>>>> +      _Formatting_scanner<_Sink_iter<_CharT>, _CharT>
>>>>>>> __scanner(__ctx, __fmt);
>>>>>>> +      __scanner._M_scan();
>>>>>>> +      return __out;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +  template<typename _Out, typename _CharT, typename _Context>
>>>>>>> +    _Out
>>>>>>> +    __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>>>>>>> +                   const basic_format_args<_Context>& __args,
>>>>>>> +                   const locale* __loc)
>>>>>>> +    {
>>>>>>> +      if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>>>>>>> +       {
>>>>>>> +         const auto __api = __format::__current_api<_CharT>();
>>>>>>>           auto __ctx = __loc == nullptr
>>>>>>> -                        ? _Context(__args, __out)
>>>>>>> -                        : _Context(__args, __out, *__loc);
>>>>>>> -         _Formatting_scanner<_Sink_iter<_CharT>, _CharT>
>>>>>>> __scanner(__ctx, __fmt);
>>>>>>> -         __scanner._M_scan();
>>>>>>> -         return __out;
>>>>>>> +                    ? _Context(__api, __args, __out)
>>>>>>> +                    : _Context(__api, __args, __out, *__loc);
>>>>>>> +         return __do_vformat_to(std::move(__out), __fmt, __ctx);
>>>>>>>         }
>>>>>>>        else if constexpr (__contiguous_char_iter<_CharT, _Out>)
>>>>>>>         {
>>>>>>> --
>>>>>>> 2.53.0
>>>>>>>
>>>>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260416/01ded712/attachment-0001.htm>


More information about the Libstdc++ mailing list