Skip to content

Commit a80c9a0

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 a80c9a0

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
// XFAIL: availability-fp_to_chars-missing
12+
13+
// The sample code is based on the bug report
14+
// https://github.com/llvm/llvm-project/issues/81590
15+
//
16+
// Tests whether this formatter does not fail to compile due to nested concept
17+
// evaluation.
18+
19+
#include <format>
20+
#include <variant>
21+
22+
struct X : std::variant<X*> {
23+
X* p = nullptr;
24+
constexpr const std::variant<X*>& decay() const noexcept { return *this; }
25+
};
26+
27+
template <>
28+
struct std::formatter<X, char> : std::formatter<std::string, char> {
29+
static constexpr auto format(const X& x, auto ctx) {
30+
if (!x.p)
31+
return ctx.out();
32+
auto m = [&](const X* t) { return std::format_to(ctx.out(), "{}", *t); };
33+
return std::visit(m, x.decay());
34+
}
35+
};
36+
37+
void bug_81590() { (void)std::format("{}", X{}); }

0 commit comments

Comments
 (0)