r256564 - [TrailingObjects] Use a different technique to determine if a getDecl

James Y Knight via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 29 08:44:11 PST 2015


Author: jyknight
Date: Tue Dec 29 10:44:11 2015
New Revision: 256564

URL: http://llvm.org/viewvc/llvm-project?rev=256564&view=rev
Log:
[TrailingObjects] Use a different technique to determine if a getDecl
member function exists on a class.

The previous trick depended on inheriting from the class it was
checking, which will fail when I start marking things 'final'.

Attempt #2: now with a special #ifdef branch for MSVC.

Hopefully *this* actually builds with all supported compilers...

Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=256564&r1=256563&r2=256564&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Tue Dec 29 10:44:11 2015
@@ -558,22 +558,32 @@ bool matchesFirstInPointerRange(const Ma
   return false;
 }
 
-/// \brief Metafunction to determine if type T has a member called getDecl.
+// Metafunction to determine if type T has a member called
+// getDecl.
+#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__clang__)
+// For old versions of MSVC, we use a weird nonstandard __if_exists
+// statement, since before MSVC2015, it was not standards-conformant
+// enough to compile the usual code below.
 template <typename T> struct has_getDecl {
-  struct Default { int getDecl; };
-  struct Derived : T, Default { };
-
-  template<typename C, C> struct CheckT;
-
-  // If T::getDecl exists, an ambiguity arises and CheckT will
-  // not be instantiable. This makes f(...) the only available
-  // overload.
-  template<typename C>
-  static char (&f(CheckT<int Default::*, &C::getDecl>*))[1];
-  template<typename C> static char (&f(...))[2];
-
-  static bool const value = sizeof(f<Derived>(nullptr)) == 2;
+  __if_exists(T::getDecl) {
+    enum { value = 1 };
+  }
+  __if_not_exists(T::getDecl) {
+    enum { value = 0 };
+  }
 };
+#else
+// There is a default template inheriting from "false_type". Then, a
+// partial specialization inherits from "true_type". However, this
+// specialization will only exist when the call to getDecl() isn't an
+// error -- it vanishes by SFINAE when the member doesn't exist.
+template <typename> struct type_sink_to_void { typedef void type; };
+template <typename T, typename = void> struct has_getDecl : std::false_type {};
+template <typename T>
+struct has_getDecl<
+    T, typename type_sink_to_void<decltype(std::declval<T>().getDecl())>::type>
+    : std::true_type {};
+#endif
 
 /// \brief Matches overloaded operators with a specific name.
 ///




More information about the cfe-commits mailing list