Although Clang trunk has been adjusted to handle our std::format_kind definition (because they need to be able to compile the GCC 15.1.0 release), it's probably better to not rely on something that they might start diagnosing again in future.
Define the primary template in terms of an immediately invoked function expression, so that we can put a static_assert(false) in the body. The diagnostic that users will see looks like this: include/c++/16.0.0/format:5470:21: error: static assertion failed 5470 | static_assert(false); // Cannot use primary template of std::format_kind | ^~~~~ libstdc++-v3/ChangeLog: PR libstdc++/120190 * include/std/format (format_kind): Adjust primary template to not depend on itself. * testsuite/std/format/ranges/format_kind_neg.cc: Adjust expected errors. Check more invalid specializations. --- Tested x86_64-linux. I haven't tested it fully with Clang, because the version of Clang in Fedora is older than the change which started rejecting the previous definition of std::format_kind, and the build in Compiler Explorer is newer than the revert of that change. libstdc++-v3/include/std/format | 19 ++++++++++++++----- .../std/format/ranges/format_kind_neg.cc | 15 ++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index bfda5895e0c0..887e891f2096 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -5464,13 +5464,22 @@ namespace __format debug_string }; - /// @cond undocumented + /** @brief A constant determining how a range should be formatted. + * + * The primary template of `std::format_kind` cannot be instantiated. + * There is a partial specialization for input ranges and you can + * specialize the variable template for your own cv-unqualified types + * that satisfy the `ranges::input_range` concept. + * + * @since C++23 + */ template<typename _Rg> - constexpr auto format_kind = - __primary_template_not_defined( - format_kind<_Rg> // you can specialize this for non-const input ranges - ); + constexpr auto format_kind = []{ + static_assert(false); // Cannot use primary template of 'std::format_kind' + return type_identity<_Rg>{}; + }(); + /// @cond undocumented template<typename _Tp> consteval range_format __fmt_kind() diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc index bf8619d3d276..b2f1b6f42201 100644 --- a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc @@ -5,9 +5,14 @@ #include <format> -template<auto> struct Tester { }; +void test() +{ + (void) std::format_kind<void>; // { dg-error "here" } + (void) std::format_kind<const void>; // { dg-error "here" } + (void) std::format_kind<int>; // { dg-error "here" } + (void) std::format_kind<int&>; // { dg-error "here" } + (void) std::format_kind<const int(&)[10]>; // { dg-error "here" } + (void) std::format_kind<void()>; // { dg-error "here" } +} -Tester<std::format_kind<const int(&)[1]>> t; // { dg-error "here" } - -// { dg-error "use of 'std::format_kind" "" { target *-*-* } 0 } -// { dg-error "primary_template_not_defined" "" { target *-*-* } 0 } +// { dg-error "static assertion failed" "" { target *-*-* } 0 } -- 2.49.0