[llvm] [Support] Simplify has_StreamOperator (NFC) (PR #159242)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 16 22:13:09 PDT 2025


https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/159242

Without this patch, we are doing a roundtrip on types.  Specifically,
if decltype(...) is well formed, std::is_same_v evaluates to a boolean
value.  We then pass the boolean value to std::enable_if_t, go through
the sizeof(char)/sizeof(double) trick, and then come back to a boolean
value.

This patch simplifies all this by having test() return
std::is_same<...>.  The "caller" attaches ::value, so effectively we
are using std::is_same<...>::value when decltype(...) is well formed,
bypassing std::enable_if_t and the sizeof(char)/sizeof(double) trick.

If we did not care about the return type of the shift operator, we
could use llvm::is_detected, but the return type check doesn't allow
us to simplify things that far.


>From 4be236df8af0719472e1a2a52acf09aeb7a0de70 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Tue, 16 Sep 2025 16:51:04 -0700
Subject: [PATCH] [Support] Simplify has_StreamOperator (NFC)

Without this patch, we are doing a roundtrip on types.  Specifically,
if decltype(...) is well formed, std::is_same_v evaluates to a boolean
value.  We then pass the boolean value to std::enable_if_t, go through
the sizeof(char)/sizeof(double) trick, and then come back to a boolean
value.

This patch simplifies all this by having test() return
std::is_same<...>.  The "caller" attaches ::value, so effectively we
are using std::is_same<...>::value when decltype(...) is well formed,
bypassing std::enable_if_t and the sizeof(char)/sizeof(double) trick.

If we did not care about the return type of the shift operator, we
could use llvm::is_detected, but the return type check doesn't allow
us to simplify things that far.
---
 llvm/include/llvm/Support/FormatVariadicDetails.h | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/Support/FormatVariadicDetails.h b/llvm/include/llvm/Support/FormatVariadicDetails.h
index fa11d56fc1ada..4002caf76675c 100644
--- a/llvm/include/llvm/Support/FormatVariadicDetails.h
+++ b/llvm/include/llvm/Support/FormatVariadicDetails.h
@@ -78,15 +78,14 @@ template <class T> class has_StreamOperator {
   using ConstRefT = const std::decay_t<T> &;
 
   template <typename U>
-  static char test(std::enable_if_t<
-                   std::is_same_v<decltype(std::declval<llvm::raw_ostream &>()
-                                           << std::declval<U>()),
-                                  llvm::raw_ostream &>,
-                   int *>);
+  static auto test(int)
+      -> std::is_same<decltype(std::declval<llvm::raw_ostream &>()
+                               << std::declval<U>()),
+                      llvm::raw_ostream &>;
 
-  template <typename U> static double test(...);
+  template <typename U> static auto test(...) -> std::false_type;
 
-  static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
+  static constexpr bool value = decltype(test<ConstRefT>(0))::value;
 };
 
 // Simple template that decides whether a type T should use the member-function



More information about the llvm-commits mailing list