Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions libcxx/include/__format/range_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {

// The n field overrides a possible m type, therefore delay applying the
// effect of n until the type has been procesed.
__parse_type(__begin, __end);
bool __has_m_specifier = __parse_type(__begin, __end);
if (__parser_.__clear_brackets_)
set_brackets({}, {});
if (__begin == __end) [[unlikely]]
Expand All @@ -87,6 +87,14 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
__ctx.advance_to(__begin);
__begin = __underlying_.parse(__ctx);

// Add "m" specifier semantics if there are no underlying specifier
if (!__has_range_underlying_spec && __has_m_specifier) {
if constexpr (__fmt_pair_like<_Tp>) { // should always be true
__underlying_.set_brackets({}, {});
__underlying_.set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
}
}

// This test should not be required if __has_range_underlying_spec is false.
// However this test makes sure the underlying formatter left the parser in
// a valid state. (Note this is not a full protection against evil parsers.
Expand Down Expand Up @@ -210,13 +218,14 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {

private:
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin, _Iterator __end) {
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_type(_Iterator& __begin, _Iterator __end) {
switch (*__begin) {
case _CharT('m'):
if constexpr (__fmt_pair_like<_Tp>) {
set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", "));
++__begin;
return true;
} else
std::__throw_format_error("Type m requires a pair or a tuple with two elements");
break;
Expand All @@ -239,6 +248,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
} else
std::__throw_format_error("Type ?s requires character type as formatting argument");
}
return false;
}

template <class _ParseContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,10 @@ void test_pair_tuple(TestFunction check, ExceptionTest check_exception, auto&& i

// *** n
check(SV("__(1, 'a'), (42, '*')___"), SV("{:_^24n}"), input);
check(SV("__(1, 'a'), (42, '*')___"), SV("{:_^24nm}"), input); // m should have no effect
check(SV("____1: 'a', 42: '*'_____"), SV("{:_^24nm}"), input);

// *** type ***
check(SV("__{(1, 'a'), (42, '*')}___"), SV("{:_^26m}"), input);
check(SV("____{1: 'a', 42: '*'}_____"), SV("{:_^26m}"), input);
check_exception("Type s requires character type as formatting argument", SV("{:s}"), input);
check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), input);
for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s"))
Expand Down