Try a completely different approach to this type trait to appease older
authorChandler Carruth <chandlerc@gmail.com>
Wed, 7 Mar 2012 12:27:35 +0000 (12:27 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 7 Mar 2012 12:27:35 +0000 (12:27 +0000)
compilers. It seems that GCC 4.3 (and likely older) simply aren't going
to do SFINAE on non-type template parameters the way Clang and modern
GCCs do...

Now we detect the implicit conversion to an integer type, and then
blacklist classes, pointers, and floating point types. This seems to
work well enough, and I'm hopeful will return the bots to life.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152227 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/type_traits.h

index 241883a02cbb38ab7588daf3205aa2718982702c..0cb8e9789dcf52d96f07157af7e3229de6bf1b71 100644 (file)
@@ -121,46 +121,44 @@ template <> struct is_integral_impl<unsigned long long> : true_type {};
 template <typename T>
 struct is_integral : is_integral_impl<T> {};
 
-namespace dont_use {
-  // Form a return type that can only be instantiated with an integral or enum
-  // types (or with nullptr_t in C++11).
-  template <typename U, U u = U()> struct check_nontype_temp_param_return_type {
-    char c[2];
-  };
-  template <typename U>
-  check_nontype_temp_param_return_type<U> check_nontype_temp_param(U*);
-  template <typename U> char check_nontype_temp_param(...);
-
-  // Form a return type that can only be instantiated with nullptr_t in C++11
-  // mode. It's harmless in C++98 mode, but this allows us to filter nullptr_t
-  // when building in C++11 mode without having to detect that mode for each
-  // different compiler.
-  struct nonce {};
-  template <typename U, nonce* u = U()>
-  struct check_nullptr_t_like_return_type { char c[2]; };
-  template <typename U>
-  check_nullptr_t_like_return_type<U> check_nullptr_t_like(U*);
-  template <typename U> char check_nullptr_t_like(...);
-} // namespace dont_use
+/// \brief Metafunction to remove reference from a type.
+template <typename T> struct remove_reference { typedef T type; };
+template <typename T> struct remove_reference<T&> { typedef T type; };
+
+/// \brief Metafunction that determines whether the given type is a pointer
+/// type.
+template <typename T> struct is_pointer : false_type {};
+template <typename T> struct is_pointer<T*> : true_type {};
+template <typename T> struct is_pointer<T* const> : true_type {};
+template <typename T> struct is_pointer<T* volatile> : true_type {};
+template <typename T> struct is_pointer<T* const volatile> : true_type {};
 
 /// \brief Metafunction that determines whether the given type is either an
 /// integral type or an enumeration type.
 ///
 /// Note that this accepts potentially more integral types than we whitelist
-/// above for is_integral, it should accept essentially anything the compiler
-/// believes is an integral type.
-template <typename T> struct is_integral_or_enum {
+/// above for is_integral because it is based on merely being convertible
+/// implicitly to an integral type.
+template <typename T> class is_integral_or_enum {
+  // Provide an overload which can be called with anything implicitly
+  // convertible to an unsigned long long. This should catch integer types and
+  // enumeration types at least. We blacklist classes with conversion operators
+  // below.
+  static double check_int_convertible(unsigned long long);
+  static char check_int_convertible(...);
+
+  typedef typename remove_reference<T>::type UnderlyingT;
+  static UnderlyingT &nonce_instance;
+
+public:
   enum {
-    value = (sizeof(char) != sizeof(dont_use::check_nontype_temp_param<T>(0)) &&
-             sizeof(char) == sizeof(dont_use::check_nullptr_t_like<T>(0)))
+    value = (!is_class<UnderlyingT>::value && !is_pointer<UnderlyingT>::value &&
+             !is_same<UnderlyingT, float>::value &&
+             !is_same<UnderlyingT, double>::value &&
+             sizeof(char) != sizeof(check_int_convertible(nonce_instance)))
   };
 };
 
-/// \brief Metafunction that determines whether the given type is a pointer
-/// type.
-template <typename T> struct is_pointer : false_type {};
-template <typename T> struct is_pointer<T*> : true_type {};
-
 // enable_if_c - Enable/disable a template based on a metafunction
 template<bool Cond, typename T = void>
 struct enable_if_c {