From e3049c4b6700bbc1021a344da25d8c971975621c Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 16 Mar 2024 20:06:38 +0100 Subject: [PATCH] [libc++][format] Fixes nested concept evaluation. Before the __formattable concept depended on itself in a contrieved example. By using the underlying concept directly the cycle is broken. Fixes https://github.com/llvm/llvm-project/issues/81590 --- libcxx/include/__format/format_arg_store.h | 3 +- .../bug_81590.compile.pass.cpp | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 libcxx/test/std/utilities/format/format.functions/bug_81590.compile.pass.cpp diff --git a/libcxx/include/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h index 066cd369eb891..23a599e995759 100644 --- a/libcxx/include/__format/format_arg_store.h +++ b/libcxx/include/__format/format_arg_store.h @@ -151,7 +151,7 @@ consteval __arg_t __determine_arg_t() { // The overload for not formattable types allows triggering the static // assertion below. template - requires(!__formattable<_Tp, typename _Context::char_type>) + requires(!__formattable_with<_Tp, _Context>) consteval __arg_t __determine_arg_t() { return __arg_t::__none; } @@ -165,7 +165,6 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu using _Dp = remove_const_t<_Tp>; constexpr __arg_t __arg = __determine_arg_t<_Context, _Dp>(); static_assert(__arg != __arg_t::__none, "the supplied type is not formattable"); - static_assert(__formattable_with<_Tp, _Context>); // Not all types can be used to directly initialize the diff --git a/libcxx/test/std/utilities/format/format.functions/bug_81590.compile.pass.cpp b/libcxx/test/std/utilities/format/format.functions/bug_81590.compile.pass.cpp new file mode 100644 index 0000000000000..127f6546ccbe7 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.functions/bug_81590.compile.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// XFAIL: availability-fp_to_chars-missing + +// The sample code is based on the bug report +// https://github.com/llvm/llvm-project/issues/81590 +// +// Tests whether this formatter does not fail to compile due to nested concept +// evaluation. + +#include +#include + +struct X : std::variant { + X* p = nullptr; + constexpr const std::variant& decay() const noexcept { return *this; } +}; + +template <> +struct std::formatter : std::formatter { + static constexpr auto format(const X& x, auto ctx) { + if (!x.p) + return ctx.out(); + auto m = [&](const X* t) { return std::format_to(ctx.out(), "{}", *t); }; + return std::visit(m, x.decay()); + } +}; + +void bug_81590() { (void)std::format("{}", X{}); }