[PATCH] [libcxx] Correct SFINAE version of is_convertible to match spec and avoid triggering unnecessary compiler diagnostics
Albert Wong
ajwong at google.com
Sat Jun 28 02:24:51 PDT 2014
Hi mclow.lists,
The SFINAE forumulation used to test convertibility did not
correctly hide the conversion failure in ane expression that would
avoid a compiler diagnostic. Switched the idiom to add one more
layer of indirection and use enable_if which fixes the problem.
Also there were a few errors with const-volatile matching causing the
partial specializaitons that handled N2255 to not trigger correctly
for array types.
The following tests now compile in gcc-4.7.
futures.async/async.pass.cpp
map.cons/move_alloc.pass.cpp
map.cons/move_assign.pass.cpp
map.modifiers/insert_iter_rv.pass.cpp
map.modifiers/insert_rv.pass.cpp
meta.rel/is_convertible.pass.cpp
multimap.cons/move_alloc.pass.cpp
multimap.cons/move_assign.pass.cpp
multimap.modifiers/insert_iter_rv.pass.cpp
multimap.modifiers/insert_rv.pass.cpp
pairs.pair/rv_pair_U_V.pass.cpp
pairs.spec/make_pair.pass.cpp
thread.once.callonce/call_once.pass.cpp
unique.ptr.runtime.ctor/default02.pass.cpp
unique.ptr.runtime.ctor/pointer02.pass.cpp
unique.ptr.single.ctor/default02.pass.cpp
unique.ptr.single.ctor/pointer02.pass.cpp
unorder.map.modifiers/emplace_hint.pass.cpp
unorder.map.modifiers/emplace.pass.cpp
unorder.map.modifiers/insert_hint_rvalue.pass.cpp
unorder.map.modifiers/insert_rvalue.pass.cpp
unord.multimap.modifiers/emplace_hint.pass.cpp
unord.multimap.modifiers/emplace.pass.cpp
unord.multimap.modifiers/insert_hint_rvalue.pass.cpp
unord.multimap.modifiers/insert_rvalue.pass.cpp
http://reviews.llvm.org/D4341
Files:
include/type_traits
Index: include/type_traits
===================================================================
--- include/type_traits
+++ include/type_traits
@@ -832,14 +832,20 @@
namespace __is_convertible_imp
{
-template <class _Tp> char __test(_Tp);
-template <class _Tp> __two __test(...);
+// Test taken directly from definition of is_convertible predicate in [meta.rel]p4.
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-template <class _Tp> _Tp&& __source();
+template <class _Tp> typename add_rvalue_reference<_Tp>::type __create();
#else
-template <class _Tp> typename remove_reference<_Tp>::type& __source();
+template <class _Tp> typename remove_reference<_Tp>::type& __create();
#endif
+template <class _Tp> char helper(_Tp);
+
+template <class _Tp, class _Tf>
+typename enable_if<sizeof(helper<_Tp>(__create<_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,
bool _IsVoid = is_void<_Tp>::value>
@@ -868,9 +874,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 +889,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, const typename remove_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, const typename remove_const<_T1>::type&&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, volatile typename remove_volatile<_T1>::type&&, 1, 0> : true_type {};
+template <class _T1> struct __is_convertible<_T1, const volatile typename remove_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 +919,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.10962.patch
Type: text/x-patch
Size: 4667 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140628/e78826fd/attachment.bin>
More information about the cfe-commits
mailing list