diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2017-09-19 15:33:51 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2017-09-19 15:33:51 +0100 |
commit | c4b06e7f1de6dff6a4c087bcf554451e9887d0f3 (patch) | |
tree | 8663e2cd36d2eb27eef959675595ee25e8f9d74b /libstdc++-v3 | |
parent | e32d238855968bce82a6cca4655298c42185508d (diff) | |
download | gcc-c4b06e7f1de6dff6a4c087bcf554451e9887d0f3.zip gcc-c4b06e7f1de6dff6a4c087bcf554451e9887d0f3.tar.gz gcc-c4b06e7f1de6dff6a4c087bcf554451e9887d0f3.tar.bz2 |
PR libstdc++/82254 fix std::is_nothrow_invocable_r w.r.t throwing conversions
PR libstdc++/82254
* include/std/type_traits (__is_invocable): Add partial specialization
for INVOKE<void> case and remove is_void<R> check from partial
specialization for INVOKE<R> case.
(__is_nt_invocable_impl): New helper for is_nothrow_invocable_r.
(is_nothrow_invocable_r): Use __is_nt_invocable_impl.
* testsuite/20_util/is_nothrow_invocable/value.cc: Add tests for
conversions that can throw or fail to convert. Use static assert
strings to explain negative results.
* testsuite/20_util/is_nothrow_invocable/value_ext.cc: Use
is_nothrow_constructible in is_nt_invocable_conv.
From-SVN: r252977
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 14 | ||||
-rw-r--r-- | libstdc++-v3/include/std/type_traits | 25 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc | 96 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc | 4 |
4 files changed, 115 insertions, 24 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 28a9609..3c75c76 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2017-09-19 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/82254 + * include/std/type_traits (__is_invocable): Add partial specialization + for INVOKE<void> case and remove is_void<R> check from partial + specialization for INVOKE<R> case. + (__is_nt_invocable_impl): New helper for is_nothrow_invocable_r. + (is_nothrow_invocable_r): Use __is_nt_invocable_impl. + * testsuite/20_util/is_nothrow_invocable/value.cc: Add tests for + conversions that can throw or fail to convert. Use static assert + strings to explain negative results. + * testsuite/20_util/is_nothrow_invocable/value_ext.cc: Use + is_nothrow_constructible in is_nt_invocable_conv. + 2017-09-18 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/81468 diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 15b0d92..036f766 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2592,7 +2592,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Result, typename _Ret> struct __is_invocable_impl<_Result, _Ret, __void_t<typename _Result::type>> - : __or_<is_void<_Ret>, is_convertible<typename _Result::type, _Ret>>::type + : is_convertible<typename _Result::type, _Ret>::type + { }; + + template<typename _Result> + struct __is_invocable_impl<_Result, void, __void_t<typename _Result::type>> + : true_type { }; template<typename _Fn, typename... _ArgTypes> @@ -2691,10 +2696,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __call_is_nothrow_<_Fn, _ArgTypes...>>::type { }; + template<typename _Result, typename _Ret, typename = void> + struct __is_nt_invocable_impl : false_type { }; + + template<typename _Result, typename _Ret> + struct __is_nt_invocable_impl<_Result, _Ret, + __void_t<typename _Result::type>> + : __and_<is_convertible<typename _Result::type, _Ret>, + is_nothrow_constructible<_Ret, typename _Result::type>> + { }; + + template<typename _Result> + struct __is_nt_invocable_impl<_Result, void, + __void_t<typename _Result::type>> + : true_type + { }; + /// std::is_nothrow_invocable_r template<typename _Ret, typename _Fn, typename... _ArgTypes> struct is_nothrow_invocable_r - : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>, + : __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>, __call_is_nothrow_<_Fn, _ArgTypes...>>::type { }; diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc index 4ccb459..dfa76aa 100644 --- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc @@ -40,6 +40,10 @@ template<typename R, typename... T> void test01() { + struct T { T(int) { } }; + struct NT { NT(int) noexcept { } }; + struct Ex { explicit Ex(int) noexcept { } }; + using func_type = void(*)(); static_assert( ! is_nt_invocable< func_type>(), ""); @@ -55,28 +59,46 @@ void test01() static_assert( ! is_nt_invocable< mem_type, int >(), ""); static_assert( ! is_nt_invocable< mem_type, int& >(), ""); - static_assert( is_nt_invocable< mem_type, X& >(), ""); - static_assert( is_nt_invocable_r< int, mem_type, X& >(), ""); - static_assert( is_nt_invocable_r< int&, mem_type, X& >(), ""); - static_assert( is_nt_invocable_r< long, mem_type, X& >(), ""); - static_assert( is_nt_invocable_r< int&, mem_type, X* >(), ""); + static_assert( is_nt_invocable< mem_type, X& >(), ""); + static_assert( is_nt_invocable_r< int, mem_type, X& >(), ""); + static_assert( is_nt_invocable_r< int&, mem_type, X& >(), ""); + static_assert( is_nt_invocable_r< long, mem_type, X& >(), ""); + static_assert( ! is_nt_invocable_r< long&, mem_type, X& >(), + "conversion fails, cannot bind long& to int"); + static_assert( is_nt_invocable_r< int&, mem_type, X* >(), ""); + + static_assert( ! is_nt_invocable_r< T, mem_type, X& >(), + "conversion throws"); + static_assert( is_nt_invocable_r< NT, mem_type, X& >(), ""); + static_assert( ! is_nt_invocable_r< Ex, mem_type, X& >(), + "conversion fails, would use explicit constructor"); using memfun_type = int (X::*)(); - static_assert( ! is_nt_invocable< memfun_type >(), ""); - static_assert( ! is_nt_invocable< memfun_type, int >(), ""); - static_assert( ! is_nt_invocable< memfun_type, int& >(), ""); - static_assert( ! is_nt_invocable< memfun_type, X& >(), ""); - static_assert( ! is_nt_invocable< memfun_type, X* >(), ""); + static_assert( ! is_nt_invocable< memfun_type >(), "no object"); + static_assert( ! is_nt_invocable< memfun_type, int >(), "no object"); + static_assert( ! is_nt_invocable< memfun_type, int& >(), "no object"); + static_assert( ! is_nt_invocable< memfun_type, X& >(), "call throws"); + static_assert( ! is_nt_invocable< memfun_type, X* >(), "call throws"); + + static_assert( ! is_nt_invocable_r< T, memfun_type, X& >(), "call throws"); + static_assert( ! is_nt_invocable_r< NT, memfun_type, X& >(), "call throws"); + static_assert( ! is_nt_invocable_r< Ex, memfun_type, X& >(), "call throws"); #if __cpp_noexcept_function_type using memfun_type_nt = int (X::*)() noexcept; - static_assert( ! is_nt_invocable< memfun_type_nt >(), ""); - static_assert( ! is_nt_invocable< memfun_type_nt, int >(), ""); - static_assert( ! is_nt_invocable< memfun_type_nt, int& >(), ""); + static_assert( ! is_nt_invocable< memfun_type_nt >(), "no object"); + static_assert( ! is_nt_invocable< memfun_type_nt, int >(), "no object"); + static_assert( ! is_nt_invocable< memfun_type_nt, int& >(), "no object"); static_assert( is_nt_invocable< memfun_type_nt, X& >(), ""); static_assert( is_nt_invocable< memfun_type_nt, X* >(), ""); + + static_assert( ! is_nt_invocable_r< T, memfun_type_nt, X& >(), + "conversion throws"); + static_assert( is_nt_invocable_r< NT, memfun_type_nt, X& >(), ""); + static_assert( ! is_nt_invocable_r< Ex, memfun_type_nt, X& >(), + "conversion fails, would use explicit constructor"); #endif struct F { @@ -89,12 +111,44 @@ void test01() }; using CF = const F; - static_assert( ! is_nt_invocable_r< int&, F >(), ""); - static_assert( is_nt_invocable_r< long&, CF >(), ""); - static_assert( ! is_nt_invocable_r< short&, F, int >(), "" ); - static_assert( is_nt_invocable_r< char&, F&, int >(), "" ); - static_assert( is_nt_invocable_r< char&, CF, int >(), "" ); - static_assert( is_nt_invocable_r< char&, CF&, int >(), "" ); - - static_assert( ! is_nt_invocable< F, int, int >(), ""); + static_assert( ! is_nt_invocable< F >(), "call throws"); + static_assert( is_nt_invocable< CF >(), ""); + + static_assert( ! is_nt_invocable_r< int&, F >(), "call throws"); + static_assert( is_nt_invocable_r< long&, CF >(), ""); + static_assert( ! is_nt_invocable_r< T, F >(), "call throws"); + static_assert( ! is_nt_invocable_r< NT, F >(), "call throws"); + static_assert( ! is_nt_invocable_r< Ex, F >(), "call throws"); + static_assert( ! is_nt_invocable_r< T, CF >(), "conversion throws"); + static_assert( is_nt_invocable_r< NT, CF >(), "" ); + static_assert( ! is_nt_invocable_r< Ex, CF >(), "conversion fails"); + + static_assert( ! is_nt_invocable< F, int >(), "call throws"); + static_assert( is_nt_invocable< F&, int >(), ""); + + static_assert( ! is_nt_invocable_r< short&, F, int >(), + "call throws" ); + static_assert( is_nt_invocable_r< char&, F&, int >(), ""); + static_assert( ! is_nt_invocable_r< T, F&, int >(), + "conversion throws"); + static_assert( is_nt_invocable_r< NT, F&, int >(), ""); + static_assert( ! is_nt_invocable_r< Ex, F&, int >(), + "conversion fails, would use explicit constructor"); + + static_assert( is_nt_invocable< CF, int >(), ""); + static_assert( is_nt_invocable< CF&, int >(), ""); + + static_assert( is_nt_invocable_r< char&, CF, int >(), ""); + static_assert( is_nt_invocable_r< char&, CF&, int >(), ""); + + static_assert( ! is_nt_invocable_r< T, CF&, int >(), + "conversion throws"); + static_assert( is_nt_invocable_r< NT, CF&, int >(), ""); + static_assert( ! is_nt_invocable_r< Ex, CF&, int >(), + "conversion fails, would use explicit constructor"); + + static_assert( ! is_nt_invocable< F, int, int >(), + "would call private member"); + static_assert( ! is_nt_invocable_r<void, F, int, int >(), + "would call private member"); } diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc index 7217324..7fd3d92 100644 --- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc @@ -27,7 +27,9 @@ template<typename... T> constexpr bool is_nt_invocable_conv(std::true_type) { using result_type = typename std::__invoke_result<T...>::type; - return std::is_void<R>::value || std::is_convertible<result_type, R>::value; + return std::is_void<R>::value + || (std::is_convertible<result_type, R>::value + && std::is_nothrow_constructible<R, result_type>::value); } template<typename R, typename... T> |