Skip to content

Commit 683f837

Browse files
committed
[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 #81590
1 parent 0847c90 commit 683f837

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

libcxx/include/__format/format_arg_store.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ consteval __arg_t __determine_arg_t() {
151151
// The overload for not formattable types allows triggering the static
152152
// assertion below.
153153
template <class _Context, class _Tp>
154-
requires(!__formattable<_Tp, typename _Context::char_type>)
154+
requires(!__formattable_with<_Tp, _Context>)
155155
consteval __arg_t __determine_arg_t() {
156156
return __arg_t::__none;
157157
}
@@ -165,7 +165,6 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu
165165
using _Dp = remove_const_t<_Tp>;
166166
constexpr __arg_t __arg = __determine_arg_t<_Context, _Dp>();
167167
static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");
168-
169168
static_assert(__formattable_with<_Tp, _Context>);
170169

171170
// Not all types can be used to directly initialize the
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
// UNSUPPORTED: c++03, c++11, c++14, c++17
9+
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
10+
11+
// The sample code is based on the bug report
12+
// https://github.com/llvm/llvm-project/issues/81590
13+
//
14+
// Tests whether this formatter does not fail to compile due to nested concept
15+
// evaluation.
16+
17+
#include <format>
18+
#include <variant>
19+
20+
struct X : std::variant<X*> {
21+
X* p = nullptr;
22+
constexpr const std::variant<X*>& decay() const noexcept { return *this; }
23+
};
24+
25+
template <>
26+
struct std::formatter<X, char> : std::formatter<std::string, char> {
27+
static constexpr auto format(const X& x, auto ctx) {
28+
if (!x.p)
29+
return ctx.out();
30+
auto m = [&](const X* t) { return std::format_to(ctx.out(), "{}", *t); };
31+
return std::visit(m, x.decay());
32+
}
33+
};
34+
35+
void bug_81590() { (void)std::format("{}", X{}); }

0 commit comments

Comments
 (0)