3943. Clarify lifetime requirements of BasicFormatter and Formatter

Section: 28.5.6.3 [format.formattable] Status: New Submitter: Mark de Wever Opened: 2023-06-01 Last modified: 2023-06-08

Priority: 3

View all other issues in [format.formattable].

View all issues with New status.

Discussion:

A bug has been filed against libc++'s format implementation. The question arose whether the parsed chrono-specs should still be available during executing the formatter's format member function. Libc++'s implementation requires this MSVC STL's implementation does not.

It turns out there is a lifetime a requirement in the Standard, but it would be good to clarify the intention of the wording. Prosed a small wording improvement and a note to clarify the intention.

Currently the format function may use elements in the range [pc.begin(), pc.end()) that have not been parsed. This does not seem to be in the spirit of the formatting library. The wording change proposes to restrict this range to the parsed range.

[2023-06-08; Reflector poll]

Set priority to 3 after reflector poll.

The proposed resolution is missing a guarantee that the parsed portion of the range is unchanged between the calls to parse and format. It must remain valid and unchanged.

Proposed resolution:

This wording is relative to N4950.

  1. Modify BasicFormatter requirements [tab:formatter.basic] as indicated:

    Table 73: BasicFormatter requirements [tab:formatter.basic]
    Expression Return type Requirement
    f.format(u, fc) FC::iterator Formats u according to the specifiers stored in
    *this, writes the output to fc.out(), and returns
    an iterator past the end of the output range.
    The output shall only depend on u, fc.locale(),
    fc.arg(n) for any value n of type size_t, and
    the elements in the parsed range of [pc.begin(), pc.end())
    from the last call to f.parse(pc).

    [Note ?: Using elements in the parsed range of [pc.begin(),
    pc.end())
    allows the formatter to store references, pointers, or
    iterators to elements in the parsed range. For example,
    formatter<chrono::day> might store the parsed chrono-specs
    (30.12 [time.format]) in a basic_string_view. — end note]

  2. Modify Formatter requirements [tab:formatter] as indicated:

    Table 74: Formatter requirements [tab:formatter]
    Expression Return type Requirement
    f.format(t, fc) FC::iterator Formats t according to the specifiers stored in
    *this, writes the output to fc.out(), and returns
    an iterator past the end of the output range.
    The output shall only depend on t, fc.locale(),
    fc.arg(n) for any value n of type size_t, and
    the elements in the parsed range of [pc.begin(), pc.end())
    from the last call to f.parse(pc).

    [Note ?: Using elements in the parsed range of [pc.begin(),
    pc.end())
    allows the formatter to store references, pointers, or
    iterators to elements in the parsed range. For example,
    formatter<chrono::day> might store the parsed chrono-specs
    (30.12 [time.format]) in a basic_string_view. — end note]