[llvm] 07e3004 - [Support] Modernize YAML traits with is_detected (NFC) (#156598)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 3 07:48:32 PDT 2025


Author: Kazu Hirata
Date: 2025-09-03T07:48:28-07:00
New Revision: 07e30043117c87f30a4505f2858a27ed0e2ea012

URL: https://github.com/llvm/llvm-project/commit/07e30043117c87f30a4505f2858a27ed0e2ea012
DIFF: https://github.com/llvm/llvm-project/commit/07e30043117c87f30a4505f2858a27ed0e2ea012.diff

LOG: [Support] Modernize YAML traits with is_detected (NFC) (#156598)

This patch modernizes has_* YAML traits with is_detected.

The resulting code should be a lot more readable because all the
SFINAE logic is hidden behind is_detected.

One note about has_FlowTraits.  The original code uses a complex trick
to detect a member variable named "flow", intentionally triggering
ambiguity with "flow" in the two base classes.  I've simplified the
check down to:

  template <class U> using check = decltype(&U::flow);

without using SameType.  The use of SameType here would make the trait
unnecessarily complicated.

While I am at it, this patch switches to "static constexpr bool".

Added: 
    

Modified: 
    llvm/include/llvm/Support/YAMLTraits.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index d29a0e4c3c783..07ac080d2c235 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -307,25 +307,21 @@ template <typename T> struct MissingTrait;
 template <class T> struct has_ScalarEnumerationTraits {
   using Signature_enumeration = void (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_enumeration, &U::enumeration> *);
+  template <class U>
+  using check =
+      SameType<Signature_enumeration, &ScalarEnumerationTraits<U>::enumeration>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, T>::value;
 };
 
 // Test if ScalarBitSetTraits<T> is defined on type T.
 template <class T> struct has_ScalarBitSetTraits {
   using Signature_bitset = void (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_bitset, &U::bitset> *);
-
-  template <typename U> static double test(...);
+  template <class U>
+  using check = SameType<Signature_bitset, &ScalarBitSetTraits<U>::bitset>;
 
-  static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, T>::value;
 };
 
 // Test if ScalarTraits<T> is defined on type T.
@@ -334,15 +330,12 @@ template <class T> struct has_ScalarTraits {
   using Signature_output = void (*)(const T &, void *, raw_ostream &);
   using Signature_mustQuote = QuotingType (*)(StringRef);
 
-  template <typename U>
-  static char test(SameType<Signature_input, &U::input> *,
-                   SameType<Signature_output, &U::output> *,
-                   SameType<Signature_mustQuote, &U::mustQuote> *);
-
-  template <typename U> static double test(...);
+  template <class U>
+  using check = std::tuple<SameType<Signature_input, &U::input>,
+                           SameType<Signature_output, &U::output>,
+                           SameType<Signature_mustQuote, &U::mustQuote>>;
 
-  static bool const value =
-      (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+  static constexpr bool value = is_detected<check, ScalarTraits<T>>::value;
 };
 
 // Test if BlockScalarTraits<T> is defined on type T.
@@ -350,14 +343,11 @@ template <class T> struct has_BlockScalarTraits {
   using Signature_input = StringRef (*)(StringRef, void *, T &);
   using Signature_output = void (*)(const T &, void *, raw_ostream &);
 
-  template <typename U>
-  static char test(SameType<Signature_input, &U::input> *,
-                   SameType<Signature_output, &U::output> *);
+  template <class U>
+  using check = std::tuple<SameType<Signature_input, &U::input>,
+                           SameType<Signature_output, &U::output>>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
+  static constexpr bool value = is_detected<check, BlockScalarTraits<T>>::value;
 };
 
 // Test if TaggedScalarTraits<T> is defined on type T.
@@ -367,114 +357,89 @@ template <class T> struct has_TaggedScalarTraits {
                                     raw_ostream &);
   using Signature_mustQuote = QuotingType (*)(const T &, StringRef);
 
-  template <typename U>
-  static char test(SameType<Signature_input, &U::input> *,
-                   SameType<Signature_output, &U::output> *,
-                   SameType<Signature_mustQuote, &U::mustQuote> *);
-
-  template <typename U> static double test(...);
+  template <class U>
+  using check = std::tuple<SameType<Signature_input, &U::input>,
+                           SameType<Signature_output, &U::output>,
+                           SameType<Signature_mustQuote, &U::mustQuote>>;
 
-  static bool const value =
-      (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, TaggedScalarTraits<T>>::value;
 };
 
 // Test if MappingContextTraits<T> is defined on type T.
 template <class T, class Context> struct has_MappingTraits {
   using Signature_mapping = void (*)(class IO &, T &, Context &);
 
-  template <typename U>
-  static char test(SameType<Signature_mapping, &U::mapping> *);
+  template <class U> using check = SameType<Signature_mapping, &U::mapping>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, MappingContextTraits<T, Context>>::value;
 };
 
 // Test if MappingTraits<T> is defined on type T.
 template <class T> struct has_MappingTraits<T, EmptyContext> {
   using Signature_mapping = void (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_mapping, &U::mapping> *);
-
-  template <typename U> static double test(...);
+  template <class U> using check = SameType<Signature_mapping, &U::mapping>;
 
-  static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, MappingTraits<T>>::value;
 };
 
 // Test if MappingContextTraits<T>::validate() is defined on type T.
 template <class T, class Context> struct has_MappingValidateTraits {
   using Signature_validate = std::string (*)(class IO &, T &, Context &);
 
-  template <typename U>
-  static char test(SameType<Signature_validate, &U::validate> *);
+  template <class U> using check = SameType<Signature_validate, &U::validate>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, MappingContextTraits<T, Context>>::value;
 };
 
 // Test if MappingTraits<T>::validate() is defined on type T.
 template <class T> struct has_MappingValidateTraits<T, EmptyContext> {
   using Signature_validate = std::string (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_validate, &U::validate> *);
-
-  template <typename U> static double test(...);
+  template <class U> using check = SameType<Signature_validate, &U::validate>;
 
-  static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, MappingTraits<T>>::value;
 };
 
 // Test if MappingContextTraits<T>::enumInput() is defined on type T.
 template <class T, class Context> struct has_MappingEnumInputTraits {
   using Signature_validate = void (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_validate, &U::enumInput> *);
+  template <class U> using check = SameType<Signature_validate, &U::enumInput>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, MappingContextTraits<T, Context>>::value;
 };
 
 // Test if MappingTraits<T>::enumInput() is defined on type T.
 template <class T> struct has_MappingEnumInputTraits<T, EmptyContext> {
   using Signature_validate = void (*)(class IO &, T &);
 
-  template <typename U>
-  static char test(SameType<Signature_validate, &U::enumInput> *);
-
-  template <typename U> static double test(...);
+  template <class U> using check = SameType<Signature_validate, &U::enumInput>;
 
-  static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, MappingTraits<T>>::value;
 };
 
 // Test if SequenceTraits<T> is defined on type T.
 template <class T> struct has_SequenceMethodTraits {
   using Signature_size = size_t (*)(class IO &, T &);
 
-  template <typename U> static char test(SameType<Signature_size, &U::size> *);
-
-  template <typename U> static double test(...);
+  template <class U> using check = SameType<Signature_size, &U::size>;
 
-  static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, SequenceTraits<T>>::value;
 };
 
 // Test if CustomMappingTraits<T> is defined on type T.
 template <class T> struct has_CustomMappingTraits {
   using Signature_input = void (*)(IO &io, StringRef key, T &v);
 
-  template <typename U>
-  static char test(SameType<Signature_input, &U::inputOne> *);
+  template <class U> using check = SameType<Signature_input, &U::inputOne>;
 
-  template <typename U> static double test(...);
-
-  static bool const value =
-      (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, CustomMappingTraits<T>>::value;
 };
 
 // has_FlowTraits<int> will cause an error with some compilers because
@@ -482,24 +447,13 @@ template <class T> struct has_CustomMappingTraits {
 // real has_FlowTraits only if the template type is a class.
 template <typename T, bool Enabled = std::is_class_v<T>> class has_FlowTraits {
 public:
-  static const bool value = false;
+  static constexpr bool value = false;
 };
 
-// Some older gcc compilers don't support straight forward tests
-// for members, so test for ambiguity cause by the base and derived
-// classes both defining the member.
 template <class T> struct has_FlowTraits<T, true> {
-  struct Fallback {
-    bool flow;
-  };
-  struct Derived : T, Fallback {};
+  template <class U> using check = decltype(&U::flow);
 
-  template <typename C>
-  static char (&f(SameType<bool Fallback::*, &C::flow> *))[1];
-
-  template <typename C> static char (&f(...))[2];
-
-  static bool const value = sizeof(f<Derived>(nullptr)) == 2;
+  static constexpr bool value = is_detected<check, T>::value;
 };
 
 // Test if SequenceTraits<T> is defined on type T
@@ -512,22 +466,18 @@ struct has_SequenceTraits
 template <class T> struct has_DocumentListTraits {
   using Signature_size = size_t (*)(class IO &, T &);
 
-  template <typename U> static char test(SameType<Signature_size, &U::size> *);
+  template <class U> using check = SameType<Signature_size, &U::size>;
 
-  template <typename U> static double test(...);
-
-  static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr)) == 1);
+  static constexpr bool value =
+      is_detected<check, DocumentListTraits<T>>::value;
 };
 
 template <class T> struct has_PolymorphicTraits {
   using Signature_getKind = NodeKind (*)(const T &);
 
-  template <typename U>
-  static char test(SameType<Signature_getKind, &U::getKind> *);
-
-  template <typename U> static double test(...);
+  template <class U> using check = SameType<Signature_getKind, &U::getKind>;
 
-  static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1);
+  static constexpr bool value = is_detected<check, PolymorphicTraits<T>>::value;
 };
 
 inline bool isNumeric(StringRef S) {


        


More information about the llvm-commits mailing list