From: James Y Knight Date: Tue, 29 Dec 2015 16:44:11 +0000 (+0000) Subject: [TrailingObjects] Use a different technique to determine if a getDecl X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=73d6e7e98df34e9e9648d11745c3700bde64a9cd;p=clang [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... git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256564 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 22068b48e7..d49909183f 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -558,22 +558,32 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, 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 struct has_getDecl { - struct Default { int getDecl; }; - struct Derived : T, Default { }; - - template struct CheckT; - - // If T::getDecl exists, an ambiguity arises and CheckT will - // not be instantiable. This makes f(...) the only available - // overload. - template - static char (&f(CheckT*))[1]; - template static char (&f(...))[2]; - - static bool const value = sizeof(f(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 struct type_sink_to_void { typedef void type; }; +template struct has_getDecl : std::false_type {}; +template +struct has_getDecl< + T, typename type_sink_to_void().getDecl())>::type> + : std::true_type {}; +#endif /// \brief Matches overloaded operators with a specific name. ///