Title
Formatting functions should throw on argument/format string mismatch in §[format.functions]
Status
c++20
Section
[format.functions]
Submitter
Great Britain

Created on 2019-11-17.00:00:00 last changed 37 months ago

Messages

Date: 2020-02-13.09:10:07

Proposed resolution:

This wording is relative to N4849.

  1. Change [format.string.general] as follows:

    -1- A format string for arguments args is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than { and }. […]

    -2- The arg-id field specifies the index of the argument in args whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id in args, the string is not a format string for args. The optional format-specifier field explicitly specifies a format for the replacement value.

    […]

    -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec does not conform to the format specifications for the argument type referred to by arg-id, the string is not a format string for args. […]

  2. Before [format.functions] insert a new sub-clause as indicated:

    20.20.? Error reporting [format.err.report]

    -?- Formatting functions throw format_error if an argument fmt is passed that is not a format string for args. They propagate exceptions thrown by operations of formatter specializations and iterators. Failure to allocate storage is reported by throwing an exception as described in [res.on.exception.handling].

  3. Modify [format.functions] as indicated:

    string vformat(string_view fmt, format_args args);
    wstring vformat(wstring_view fmt, wformat_args args);
    string vformat(const locale& loc, string_view fmt, format_args args);
    wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
    

    -6- […]

    -7- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class Out>
      Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, string_view fmt,
                     format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, wstring_view fmt,
                     format_args_t<Out, wchar_t> args);
    

    […]

    -15- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          string_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          wstring_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, string_view fmt,
                                          const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, wstring_view fmt,
                                          const Args&... args);
    

    […]

    -21- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class... Args>
      size_t formatted_size(string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(wstring_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
    

    […]

    -25- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

Date: 2020-02-15.00:00:00

[ 2020-02-12, Prague; LWG discussion ]

Option A is the only one we look at to resolve LWG 3336 as well. During the discussions some wording refinements have been suggested that are integrated below.

Date: 2020-02-13.09:04:01

Addresses GB 229

Formatting functions don't allow throwing on incorrect arguments. std::format is only allowed to throw if fmt is not a format string, but the intention is it also throws for errors during formatting, e.g. there are fewer arguments than required by the format string.

Proposed change:

Allow exceptions even when the format string is valid. Possibly state the Effects: more precisely.

Victor Zverovich:

LEWG approved resolution of this NB comment as an LWG issue.

Previous resolution [SUPERSEDED]:

This wording is relative to N4835.

[Drafting Note: Depending on whether LWG 3336's wording has been accepted when this issue's wording has been accepted, two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A (LWG 3336 has been accepted)

  1. Change [format.string.general] as follows:

    -1- A format string for arguments args is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than { and }. […]

    -2- The arg-id field specifies the index of the argument in args whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id in args, the string is not a format string. The optional format-specifier field explicitly specifies a format for the replacement value.

    […]

    -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec doesn't conform to the format specifications for the argument in args referred to by arg-id, the string is not a format string. […]

  2. Before [format.functions] insert a new sub-clause as indicated:

    20.20.? Error reporting [format.err.report]

    -?- Formatting functions throw exceptions to report formatting and other errors. They throw format_error if an argument fmt is passed that is not a format string for arguments args and propagate exceptions thrown by formatter specializations and iterator operations. Failure to allocate storage is reported by throwing an exception as described in [res.on.exception.handling].

  3. Modify [format.functions] as indicated:

    string vformat(string_view fmt, format_args args);
    wstring vformat(wstring_view fmt, wformat_args args);
    string vformat(const locale& loc, string_view fmt, format_args args);
    wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
    

    -6- […]

    -7- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class Out>
      Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, string_view fmt,
                     format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, wstring_view fmt,
                     format_args_t<Out, wchar_t> args);
    

    […]

    -15- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          string_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          wstring_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, string_view fmt,
                                          const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, wstring_view fmt,
                                          const Args&... args);
    

    […]

    -21- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

    […]
    template<class... Args>
      size_t formatted_size(string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(wstring_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
    

    […]

    -25- Throws: format_error if fmt is not a format stringAs specified in [format.err.report].

Option B (LWG 3336 has not been accepted)

  1. Change [format.string.general] as follows:

    -1- A format string for arguments args is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than { and }. […]

    -2- The arg-id field specifies the index of the argument in args whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id in args, the string is not a format string. The optional format-specifier field explicitly specifies a format for the replacement value.

    […]

    -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec doesn't conform to the format specifications for the argument in args referred to by arg-id, the string is not a format string. […]

  2. Modify [format.functions] as indicated:

    string vformat(string_view fmt, format_args args);
    wstring vformat(wstring_view fmt, wformat_args args);
    string vformat(const locale& loc, string_view fmt, format_args args);
    wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
    

    -6- […]

    -7- Throws: format_error if fmt is not a format string for args.

    […]
    template<class Out>
      Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, string_view fmt,
                     format_args_t<Out, char> args);
    template<class Out>
      Out vformat_to(Out out, const locale& loc, wstring_view fmt,
                     format_args_t<Out, wchar_t> args);
    

    […]

    -15- Throws: format_error if fmt is not a format string for args.

    […]
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          string_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          wstring_view fmt, const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, string_view fmt,
                                          const Args&... args);
    template<class Out, class... Args>
      format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                          const locale& loc, wstring_view fmt,
                                          const Args&... args);
    

    […]

    -21- Throws: format_error if fmt is not a format string for args.

    […]
    template<class... Args>
      size_t formatted_size(string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(wstring_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
    template<class... Args>
      size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
    

    […]

    -25- Throws: format_error if fmt is not a format string for args.

History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2020-02-24 16:02:59adminsetstatus: immediate -> wp
2020-02-13 09:32:20adminsetstatus: new -> immediate
2020-02-13 09:04:01adminsetmessages: + msg11046
2019-11-23 14:09:21adminsetmessages: + msg10838
2019-11-17 00:00:00admincreate