Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] format("{0:#c}", 77) should be accepted #106136

Open
StephanTLavavej opened this issue Aug 26, 2024 · 1 comment
Open

[libc++] format("{0:#c}", 77) should be accepted #106136

StephanTLavavej opened this issue Aug 26, 2024 · 1 comment
Assignees
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Comments

@StephanTLavavej
Copy link
Member

https://godbolt.org/z/vac7s4rKn

#include <cassert>
#include <format>
#include <string>
using namespace std;

int main() {
    // Everyone accepts:
    assert(format("{0:#}", 77) == "77");
    assert(format("{0:#d}", 77) == "77");
    assert(format("{0:#b}", 77) == "0b1001101");
    assert(format("{0:#B}", 77) == "0B1001101");
    assert(format("{0:#o}", 77) == "0115");
    assert(format("{0:#x}", 77) == "0x4d");
    assert(format("{0:#X}", 77) == "0X4D");
    assert(format("{0:c}", 77) == "M");

    // libstdc++ 14.2 accepts, libc++ 18.1 and microsoft/STL 17.10 reject:
    assert(format("{0:#c}", 77) == "M");

    // 77 is an int, which is an arithmetic type other than charT and bool.
    // 'c' is an integer presentation type.
    // Therefore, I conclude that formatting 77 with "{0:#c}" is doubly valid.
    // Here's the Standardese:

    // N4988 [format.string.std]/7:
    // "The # option causes the alternate form to be used for the conversion.
    // This option is valid for arithmetic types other than charT and bool
    // or when an integer presentation type is specified, and not otherwise."

    // N4988 [format.string.std]/21:
    // "The available integer presentation types for integral types other than bool and charT
    // are specified in Table 72."

    // Table 72 - Meaning of type options for integer types [tab:format.type.int]
    // Type | Meaning
    // -----|--------
    // b    | to_chars(first, last, value, 2); the base prefix is 0b.
    // B    | The same as b, except that the base prefix is 0B.
    // c    | Copies the character static_cast<charT>(value) to the output.
    //      | Throws format_error if value is not in the range of representable values for charT.
    // [...]
}
<source>:18:19: error: call to consteval function 'std::basic_format_string<char, int>::basic_format_string<char[7]>' is not a constant expression
   18 |     assert(format("{0:#c}", 77) == "M");
      |                   ^
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/parser_std_format_spec.h:462:9: note: non-constexpr function '__throw_format_error' cannot be used in a constant expression
  462 |         std::__throw_format_error("The format specifier does not allow the alternate form option");
      |         ^
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/parser_std_format_spec.h:898:3: note: in call to '__parser.__validate({0, 0, 0, 0, 1, 1, 0, 0, 1}, &"an integer"[0], 4294967295)'
  898 |   __parser.__validate(__format_spec::__fields_bool, __id);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/parser_std_format_spec.h:905:3: note: in call to '__process_display_type_bool_string<char>(__formatter.__formatter_integer::__parser_, &"an integer"[0])'
  905 |   __format_spec::__process_display_type_bool_string(__parser, __id);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/parser_std_format_spec.h:964:5: note: in call to '__process_display_type_char<char>(__formatter.__formatter_integer::__parser_, &"an integer"[0])'
  964 |     __format_spec::__process_display_type_char(__parser, __id);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/formatter_integer.h:39:5: note: in call to '__process_parsed_integer<char>(__formatter.__formatter_integer::__parser_, &"an integer"[0])'
   39 |     __format_spec::__process_parsed_integer(__parser_, "an integer");
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_functions.h:183:26: note: in call to '__formatter.parse<std::basic_format_parse_context<char>>(basic_format_parse_context<char>{this->__str_, sizeof...(_Args)})'
  183 |   __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_functions.h:206:12: note: in call to '__compile_time_validate_argument<char, int, false>(basic_format_parse_context<char>{this->__str_, sizeof...(_Args)}, _Context{__types_.data(), __handles_.data(), sizeof...(_Args)})'
  206 |     return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx);
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_functions.h:275:7: note: in call to '__compile_time_visit_format_arg<char>(basic_format_parse_context<char>{this->__str_, sizeof...(_Args)}, _Context{__types_.data(), __handles_.data(), sizeof...(_Args)}, 3)'
  275 |       __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_functions.h:316:20: note: in call to '__handle_replacement_field<const char *, std::basic_format_parse_context<char>, std::__format::__compile_time_basic_format_context<char>>(&"{0:#c}"[1], &"{0:#c}"[6], basic_format_parse_context<char>{this->__str_, sizeof...(_Args)}, _Context{__types_.data(), __handles_.data(), sizeof...(_Args)})'
  316 |         __begin  = __format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_functions.h:371:5: note: in call to '__vformat_to<std::basic_format_parse_context<char>, std::__format::__compile_time_basic_format_context<char>>(basic_format_parse_context<char>{this->__str_, sizeof...(_Args)}, _Context{__types_.data(), __handles_.data(), sizeof...(_Args)})'
  371 |     __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)},
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  372 |                            _Context{__types_.data(), __handles_.data(), sizeof...(_Args)});
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:18:19: note: in call to 'basic_format_string<char[7]>("{0:#c}")'
   18 |     assert(format("{0:#c}", 77) == "M");
      |                   ^~~~~~~~
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
   93 |      (static_cast <bool> (expr)                                         \
      |                           ^~~~
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__format/format_error.h:38:52: note: declared here
   38 | _LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_format_error(const char* __s) {
      |                                                    ^
1 error generated.
@github-actions github-actions bot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Aug 26, 2024
@StephanTLavavej
Copy link
Member Author

Over in microsoft/STL#4918 @CaseyCarter noted that we should ask the LWG what to do here (the sign, hash, and zero modifiers are all affected) before changing our implementations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

No branches or pull requests

4 participants
@mordante @StephanTLavavej and others