Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix format a long value with formatter#2768

Merged
StephanTLavavej merged 9 commits intomicrosoft:mainfrom
fsb4000:fix2765
Jun 12, 2022
Merged

fix format a long value with formatter#2768
StephanTLavavej merged 9 commits intomicrosoft:mainfrom
fsb4000:fix2765

Conversation

@fsb4000
Copy link
Copy Markdown
Contributor

@fsb4000 fsb4000 commented Jun 7, 2022

Fixes #2765

Although @cpplearner wrote everything in the issue, I was able to write

typename _Format_arg_traits<_FormatContext>::template _Storage_type<_Ty>

correctly only the third time :)

@fsb4000 fsb4000 requested a review from a team as a code owner June 7, 2022 21:05
@fsb4000 fsb4000 changed the title allow format a long value with formatter allow format a long value with custom formatter Jun 7, 2022
@fsb4000 fsb4000 changed the title allow format a long value with custom formatter fix format a long value with formatter Jun 7, 2022
@StephanTLavavej StephanTLavavej added bug Something isn't working format C++20/23 format labels Jun 7, 2022
@StephanTLavavej

This comment was marked as resolved.

@cpplearner
Copy link
Copy Markdown
Contributor

P0355R7_calendars_and_time_zones_formatting is failing with:

D:\build\out\inc\format(3148) : Assertion failed: The custom handler should be structurally unreachable for _Arg_formatter

This seems to be because std::string gets stored as a std::basic_format_arg::handle, which means this function is unused:

STL/stl/inc/format

Lines 1778 to 1780 in 17fde2c

template <class _Traits, class _Alloc>
static auto _Phony_basic_format_arg_constructor(const basic_string<_Char_type, _Traits, _Alloc>&)
-> basic_string_view<_Char_type>; // not defined

Maybe the constrained overload is considered to be more specialized?

STL/stl/inc/format

Lines 1744 to 1745 in 17fde2c

template <_Has_formatter<_Context> _Ty>
static auto _Phony_basic_format_arg_constructor(_Ty&&) {

Comment thread tests/std/tests/P0645R10_text_formatting_formatting/test.cpp Outdated
Comment thread tests/std/tests/P0645R10_text_formatting_formatting/test.cpp Outdated
Comment thread stl/inc/format Outdated
@StephanTLavavej
Copy link
Copy Markdown
Member

Thanks for fixing this bug! I pushed minor stylistic changes and a small test coverage increase - please meow if you disagree.

Comment thread tests/std/tests/P0645R10_text_formatting_formatting/test.cpp Outdated
@StephanTLavavej
Copy link
Copy Markdown
Member

Thanks @cpplearner for noticing that P0645R10_text_formatting_custom_formatting already has machinery that's identical to Box<T>:

template <class T>
struct custom_formattable_type {
T val;
};
template <class T, class charT>
struct std::formatter<custom_formattable_type<T>, charT> : std::formatter<T, charT> {
template <class FC>
auto format(const custom_formattable_type<T>& val, FC& format_ctx) const {
return std::formatter<T, charT>::format(val.val, format_ctx);
}
};

I verified that adding test coverage for long here will fail without @fsb4000's fix. To be comprehensive, I also added coverage for unsigned long and long double.

@fsb4000
Copy link
Copy Markdown
Contributor Author

fsb4000 commented Jun 8, 2022

This seems to be because std::string gets stored as a std::basic_format_arg::handle, which means this function is unused:

No, std::string is ok, I have debugged the test.
The error is from the asserts:

test_information_classes<wchar_t>();

test_information_classes<char>(); works OK. (strange)

and inside test_information_classes

const local_info nonexistent2 = la_tz->get_info(LA::Std_1.local_end());
// N4885 [time.zone.info.sys]/7: "Effects: Streams out the sys_info object r in an unspecified format."
// N4885 [time.zone.info.local]/3: "Effects: Streams out the local_info object r in an unspecified format."
empty_braces_helper(sys1,
STR("begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: AEST"),
STR("begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: GMT+10"));

All empty_braces_helper tests with local_info and sys_info are failed

void empty_braces_helper(
const Arg& val, const CharT* const expected, const same_as<const CharT*> auto... alternatives) {
// N4885 [time.format]/6: "If the chrono-specs is omitted, the chrono object is formatted
// as if by streaming it to std::ostringstream os and copying os.str() through the output iterator
// of the context with additional padding and adjustments as specified by the format specifiers."
const auto result = format(STR("{}"), val);

So format local_info is stored as a std::basic_format_arg::handle

@cpplearner
Copy link
Copy Markdown
Contributor

  • format(STR("{}"), val) calls operator<<;
  • operator<< calls _Widen_string<_CharT>(_Val.abbrev);
  • _Widen_string returns a const string& when CharT is char, but returns a wstring when CharT is wchar_t.

That const probably makes a difference here.

#include <format>
#include <string>

using namespace std;

using A = _Format_arg_traits<format_context>::_Storage_type<string>;
using B = _Format_arg_traits<format_context>::_Storage_type<const string>;

static_assert(is_same_v<A, basic_format_arg<format_context>::handle>);
static_assert(is_same_v<B, string_view>);

@fsb4000
Copy link
Copy Markdown
Contributor Author

fsb4000 commented Jun 8, 2022

well done @cpplearner !
So can we change

template <class _Traits, class _Alloc> 
 static auto _Phony_basic_format_arg_constructor(const basic_string<_Char_type, _Traits, _Alloc>&) 
     -> basic_string_view<_Char_type>; // not defined 

to

template <class _Traits, class _Alloc> 
 static auto _Phony_basic_format_arg_constructor(basic_string<_Char_type, _Traits, _Alloc>) 
     -> basic_string_view<_Char_type>; // not defined 

?

Comment thread stl/inc/format
Comment thread stl/inc/format
Comment thread stl/inc/format
@StephanTLavavej StephanTLavavej removed their assignment Jun 8, 2022
Comment thread stl/inc/format Outdated
@StephanTLavavej StephanTLavavej self-requested a review June 9, 2022 00:06
@fsb4000
Copy link
Copy Markdown
Contributor Author

fsb4000 commented Jun 9, 2022

Yes, I did it intentionally because we don't modify basic_format_arg.
I would store char* as const char* if I don't plan to modify it.
But now I am unsure, maybe the const is not needed...

@StephanTLavavej StephanTLavavej self-assigned this Jun 9, 2022
Comment thread stl/inc/format
Copy link
Copy Markdown
Contributor

@barcharcraz barcharcraz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, despite this not doing what the standard says for basic_string&

Agree with Casey that we need to reformulate how this overload set works, it's been a very consistent source of bugs in both our implementation and the standard.

@barcharcraz barcharcraz removed their assignment Jun 10, 2022
@StephanTLavavej StephanTLavavej self-assigned this Jun 10, 2022
@StephanTLavavej
Copy link
Copy Markdown
Member

I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

@StephanTLavavej StephanTLavavej merged commit 1385898 into microsoft:main Jun 12, 2022
@StephanTLavavej
Copy link
Copy Markdown
Member

Thanks for the bugfix and targeted overhaul here, improving our implementation beyond the Standard itself! 😹 🐞 🎉

@fsb4000 fsb4000 deleted the fix2765 branch June 12, 2022 13:20
fsb4000 added a commit to fsb4000/STL that referenced this pull request Aug 13, 2022
Co-authored-by: S. B. Tam <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working format C++20/23 format

Projects

None yet

Development

Successfully merging this pull request may close these issues.

<format>: Cannot format a long value with formatter

6 participants