[PATCH] [libcxx] Correct SFINAE version of is_convertible to match spec and avoid triggering unnecessary compiler diagnostics

Albert Wong ajwong at google.com
Fri Aug 1 14:29:37 PDT 2014


Addressed comments. PTAL

http://reviews.llvm.org/D4341

Files:
  include/type_traits

Index: include/type_traits
===================================================================
--- include/type_traits
+++ include/type_traits
@@ -832,13 +832,15 @@
 
 namespace __is_convertible_imp
 {
-template <class _Tp> char  __test(_Tp);
-template <class _Tp> __two __test(...);
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-template <class _Tp> _Tp&& __source();
-#else
-template <class _Tp> typename remove_reference<_Tp>::type& __source();
-#endif
+// Test derived from definition of is_convertible predicate in [meta.rel]p4.
+// declval() is used instead adding a new create() function because the
+// definitions are identical.
+template <class _Tp> char __helper(_Tp);
+
+template <class _Tp, class _Tf>
+typename enable_if<sizeof(__helper<_Tp>(declval<_Tf>())) == 1, char>::type
+    __test(int);
+template <class _Tp, class _Tf> __two __test(...);
 
 template <class _Tp, bool _IsArray =    is_array<_Tp>::value,
                      bool _IsFunction = is_function<_Tp>::value,
@@ -868,9 +870,9 @@
 struct __is_convertible
     : public integral_constant<bool,
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-        sizeof(__is_convertible_imp::__test<_T2>(__is_convertible_imp::__source<_T1>())) == 1
+        sizeof(__is_convertible_imp::__test<_T2, _T1>(1)) == 1
 #else
-        sizeof(__is_convertible_imp::__test<_T2>(__is_convertible_imp::__source<_T1>())) == 1
+        sizeof(__is_convertible_imp::__test<_T2, _T1>(1)) == 1
          && !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value
               && (!is_const<typename remove_reference<_T2>::type>::value
                   || is_volatile<typename remove_reference<_T2>::type>::value)
@@ -883,12 +885,12 @@
 
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 1, 0> : false_type {};
 
-template <class _T1> struct __is_convertible<_T1, const _T1&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, typename add_const<_T1>::type&, 1, 0> : true_type {};
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 template <class _T1> struct __is_convertible<_T1, _T1&&, 1, 0> : true_type {};
-template <class _T1> struct __is_convertible<_T1, const _T1&&, 1, 0> : true_type {};
-template <class _T1> struct __is_convertible<_T1, volatile _T1&&, 1, 0> : true_type {};
-template <class _T1> struct __is_convertible<_T1, const volatile _T1&&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, typename add_const<_T1>::type&&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, typename add_volatile<_T1>::type&&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, typename add_cv<_T1>::type&&, 1, 0> : true_type {};
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2*, 1, 0>
@@ -913,18 +915,22 @@
 template <class _T1>            struct __is_convertible<_T1, _T1*volatile, 2, 0>       : public true_type {};
 template <class _T1>            struct __is_convertible<_T1, _T1*const volatile, 2, 0> : public true_type {};
 
+// Per N2255 on is_convertible, void -> !void is not convertible.
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 3, 0> : public false_type {};
 
+// Per N2255 on is_convertible, * -> array is not converitble.
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 0, 1> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 1, 1> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 2, 1> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 3, 1> : public false_type {};
 
+// Per N2255 on is_convertible, * -> function is not converitble.
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 0, 2> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 1, 2> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 2, 2> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 3, 2> : public false_type {};
 
+// Per N2255 on is_convertible, only void -> void is convertible.
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 0, 3> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 1, 3> : public false_type {};
 template <class _T1, class _T2> struct __is_convertible<_T1, _T2, 2, 3> : public false_type {};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D4341.12119.patch
Type: text/x-patch
Size: 4508 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140801/990005b9/attachment.bin>


More information about the cfe-commits mailing list