libstdc++: Fix constification in range_formatter::format [PR109162]
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 = remove_reference_t<_Rg> is const 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<R> and range_reference_t<const R> have different types (modulo remove_cvref_t) for std::vector<bool> (::reference and bool) or flat_map<T, U> (pair<const T&, U&> and pair<const T&, const U&>). PR libstdc++/109162 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. Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
fa99720e9f
commit
aef8797522
2 changed files with 30 additions and 3 deletions
|
@ -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_t<_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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue