On Wed, 16 Apr 2025 at 12:54, Tomasz Kamiński <tkami...@redhat.com> wrote:
>
> The _Rg is deduced to lvalue reference for the lvalue arguments,
> and in such case __format::__maybe_const_range<_Rg, _CharT> is always _Rg
> (adding const to reference does not change behavior).
>
> Now we correctly check if _Range = const remove_reference_t<_Rg> is
> formattable range, furthermore as range_formatter<T> can only format
> ranges of values of type (possibly const) _Tp, we additional check if the
> remove_cvref_t<range_reference_t<const _Range>> is _Tp.
>
> The range_reference_t<T> and range_reference_t<const T> have different
> type (module remove_cvref_t) for std::vector<bool> (::reference and bool)

s/module/modulo/ ?

OK with that tweak.

> or flat_map<T, U> (pair<const T&, U&> and pair<const T&, const U&>).
>
>         PR libstdc++/PR109162
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/format (range_formatter::format): Format const range,
>         only if reference type is not changed.
>         * testsuite/std/format/ranges/formatter.cc: New tests.
> ---
> Testing on x86_64-linux, test for *format* passed.
> OK for trunk?
>
>  libstdc++-v3/include/std/format               | 11 +++++++---
>  .../testsuite/std/format/ranges/formatter.cc  | 22 +++++++++++++++++++
>  2 files changed, 30 insertions(+), 3 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
> index b1455977c65..3ae1fc1877c 100644
> --- a/libstdc++-v3/include/std/format
> +++ b/libstdc++-v3/include/std/format
> @@ -5634,9 +5634,14 @@ namespace __format
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
>         {
> -         using __maybe_const_range
> -           = __format::__maybe_const_range<_Rg, _CharT>;
> -         return _M_format<__maybe_const_range>(__rg, __fc);
> +         using _Range = remove_reference<_Rg>;
> +         if constexpr (__format::__const_formattable_range<_Range, _CharT>)
> +         {
> +           using _CRef = ranges::range_reference_t<const _Range>;
> +           if constexpr (same_as<remove_cvref_t<_CRef>, _Tp>)
> +             return _M_format<const _Range>(__rg, __fc);
> +         }
> +         return _M_format(__rg, __fc);
>         }
>
>      private:
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc 
> b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> index a4f5d9210dd..00ce9f6dd0c 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> @@ -1,5 +1,6 @@
>  // { dg-do run { target c++23 } }
>
> +#include <flat_map>
>  #include <format>
>  #include <testsuite_hooks.h>
>  #include <vector>
> @@ -138,6 +139,26 @@ test_nested()
>    VERIFY( res == "+<01; 02; 11; 12>+" );
>  }
>
> +struct MyFlatMap : std::flat_map<int, int>
> +{
> +  using std::flat_map<int, int>::flat_map;
> +};
> +
> +template<typename CharT>
> +struct std::formatter<MyFlatMap, CharT>
> +  // This cannot apply format BitVector const&, because formatted type would
> +  // be std::pair<int const&, int const&>, and formatter for
> +  // pair<int const&, int> cannot format it.
> +  : std::range_formatter<MyFlatMap::reference>
> +{};
> +
> +void test_const_ref_type_mismatch()
> +{
> +  MyFlatMap m{{1, 11}, {2, 22}};
> +  std::string res = std::format("{:m}", m);
> +  VERIFY( res == "{1: 11, 2: 22}" );
> +}
> +
>  template<typename T, typename CharT>
>  using VectorFormatter = std::formatter<std::vector<T>, CharT>;
>
> @@ -146,4 +167,5 @@ int main()
>    test_outputs<std::range_formatter>();
>    test_outputs<VectorFormatter>();
>    test_nested();
> +  test_const_ref_type_mismatch();
>  }
> --
> 2.49.0
>

Reply via email to