https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127219

            Bug ID: 127219
           Summary: <format>: make __valid_types_for_check_dynamic_spec
                    static so  check_dynamic_spec<Ts...> works with clang
                    and EDG
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: stevensudit at gmail dot com
  Target Milestone: ---
              Host: x86_64-linux-gnu
            Target: x86_64-linux-gnu
             Build: x86_64-linux-gnu

Created attachment 65507
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65507&action=edit
test: user formatter calling check_dynamic_spec

In C++26 mode a user formatter that calls
basic_format_parse_context::check_dynamic_spec<Ts...>(id) does not
compile with clang or EDG on top of libstdc++ (attached
format_check_dynamic_spec.cc):

  $ clang++ -std=c++26 -fsyntax-only format_check_dynamic_spec.cc
  format:343:18: error: static assertion expression is not an integral
    constant expression
  format_check_dynamic_spec.cc:28:10: note: in instantiation of function
    template specialization 'std::basic_format_parse_context<char>::
    check_dynamic_spec<int, unsigned int>' requested here
  format:343:18: note: implicit use of 'this' pointer is only allowed
    within the evaluation of a call to a 'constexpr' member function

EDG 6.9 (Compiler Explorer, --c++26 with the gcc 16.1 headers) says the
same thing at the same line: "expression must have a constant value",
"the value of *this cannot be used as a constant". g++ 16.2 and trunk
accept the file. Reproduced with clang 20.1, 21.1, 22.1, 23.1 and trunk
against libstdc++ 15.2, 16.2 and trunk.

The line is

  static_assert(__valid_types_for_check_dynamic_spec<_Ts...>(), ...);

in check_dynamic_spec (format:343). __valid_types_for_check_dynamic_spec
is a non-static consteval member, so the call is
(*this).__valid_types_for_check_dynamic_spec<_Ts...>(), evaluated by the
static_assert rather than as part of a call to a constexpr member
function, and everything hinges on `this` being usable there. After
P2280R4 ([expr.const]/5.1.2: `this` as the postfix-expression of an
implicit or explicit class member access) it is, and the function never
reads through the pointer. So the header is correct and gcc is right to
accept it. clang (llvm/llvm-project issue 191104, open) and EDG have not
caught up with that part of P2280R4; MSVC has. The attached
reduce_b_implicit_this.cc has the same shape without <format>: gcc trunk
and MSVC 19 accept it, clang trunk and EDG 6.9 reject it.

Since libstdc++ supports being used from clang, it seems worth stepping
around. __valid_types_for_check_dynamic_spec uses no non-static member,
so declaring it static removes the `this` and changes nothing else. The
one-word patch against trunk is attached; clang 23.1 and trunk g++ then
both accept the test against the trunk headers. The diagnosis was made
with LLM assistance (Claude, Anthropic), which I am noting per
https://gcc.gnu.org/ai-policy.html. I can send the patch to libstdc++@
with a ChangeLog and Assisted-by tag if that is useful, though it is
probably quicker for you to just make the change.

testsuite/std/format/parse_ctx.cc already exercises
check_dynamic_spec<Ts...>, so no new test seems needed; the testsuite
runs under g++, which accepts either spelling.

Reply via email to