[libcxx-commits] [libcxx] [libc++][format] Fixes nested concept evaluation. (PR #85548)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sat Mar 16 12:10:59 PDT 2024


https://github.com/mordante created https://github.com/llvm/llvm-project/pull/85548

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

>From 154ef3c6653ffac88d048299190696c729bdabcd Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
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                | 35 +++++++++++++++++++
 2 files changed, 36 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 066cd369eb8918..23a599e9957599 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 <class _Context, class _Tp>
-  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 00000000000000..0969d3bc21dfad
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/bug_81590.compile.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// 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 <format>
+#include <variant>
+
+struct X : std::variant<X*> {
+  X* p = nullptr;
+  constexpr const std::variant<X*>& decay() const noexcept { return *this; }
+};
+
+template <>
+struct std::formatter<X, char> : std::formatter<std::string, char> {
+  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{}); }



More information about the libcxx-commits mailing list