Skip to content

Commit c52a6a5

Browse files
author
redi
committed
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@252977 138bc75d-0d04-0410-961f-82ee72b054a4
1 parent a0c6c7c commit c52a6a5

File tree

4 files changed

+115
-24
lines changed

4 files changed

+115
-24
lines changed

libstdc++-v3/ChangeLog

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
2017-09-19 Jonathan Wakely <[email protected]>
2+
3+
PR libstdc++/82254
4+
* include/std/type_traits (__is_invocable): Add partial specialization
5+
for INVOKE<void> case and remove is_void<R> check from partial
6+
specialization for INVOKE<R> case.
7+
(__is_nt_invocable_impl): New helper for is_nothrow_invocable_r.
8+
(is_nothrow_invocable_r): Use __is_nt_invocable_impl.
9+
* testsuite/20_util/is_nothrow_invocable/value.cc: Add tests for
10+
conversions that can throw or fail to convert. Use static assert
11+
strings to explain negative results.
12+
* testsuite/20_util/is_nothrow_invocable/value_ext.cc: Use
13+
is_nothrow_constructible in is_nt_invocable_conv.
14+
115
2017-09-18 Jonathan Wakely <[email protected]>
216

317
PR libstdc++/81468

libstdc++-v3/include/std/type_traits

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2592,7 +2592,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
25922592

25932593
template<typename _Result, typename _Ret>
25942594
struct __is_invocable_impl<_Result, _Ret, __void_t<typename _Result::type>>
2595-
: __or_<is_void<_Ret>, is_convertible<typename _Result::type, _Ret>>::type
2595+
: is_convertible<typename _Result::type, _Ret>::type
2596+
{ };
2597+
2598+
template<typename _Result>
2599+
struct __is_invocable_impl<_Result, void, __void_t<typename _Result::type>>
2600+
: true_type
25962601
{ };
25972602

25982603
template<typename _Fn, typename... _ArgTypes>
@@ -2691,10 +2696,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
26912696
__call_is_nothrow_<_Fn, _ArgTypes...>>::type
26922697
{ };
26932698

2699+
template<typename _Result, typename _Ret, typename = void>
2700+
struct __is_nt_invocable_impl : false_type { };
2701+
2702+
template<typename _Result, typename _Ret>
2703+
struct __is_nt_invocable_impl<_Result, _Ret,
2704+
__void_t<typename _Result::type>>
2705+
: __and_<is_convertible<typename _Result::type, _Ret>,
2706+
is_nothrow_constructible<_Ret, typename _Result::type>>
2707+
{ };
2708+
2709+
template<typename _Result>
2710+
struct __is_nt_invocable_impl<_Result, void,
2711+
__void_t<typename _Result::type>>
2712+
: true_type
2713+
{ };
2714+
26942715
/// std::is_nothrow_invocable_r
26952716
template<typename _Ret, typename _Fn, typename... _ArgTypes>
26962717
struct is_nothrow_invocable_r
2697-
: __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
2718+
: __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
26982719
__call_is_nothrow_<_Fn, _ArgTypes...>>::type
26992720
{ };
27002721

libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ template<typename R, typename... T>
4040

4141
void test01()
4242
{
43+
struct T { T(int) { } };
44+
struct NT { NT(int) noexcept { } };
45+
struct Ex { explicit Ex(int) noexcept { } };
46+
4347
using func_type = void(*)();
4448
static_assert( ! is_nt_invocable< func_type>(), "");
4549

@@ -55,28 +59,46 @@ void test01()
5559
static_assert( ! is_nt_invocable< mem_type, int >(), "");
5660
static_assert( ! is_nt_invocable< mem_type, int& >(), "");
5761

58-
static_assert( is_nt_invocable< mem_type, X& >(), "");
59-
static_assert( is_nt_invocable_r< int, mem_type, X& >(), "");
60-
static_assert( is_nt_invocable_r< int&, mem_type, X& >(), "");
61-
static_assert( is_nt_invocable_r< long, mem_type, X& >(), "");
62-
static_assert( is_nt_invocable_r< int&, mem_type, X* >(), "");
62+
static_assert( is_nt_invocable< mem_type, X& >(), "");
63+
static_assert( is_nt_invocable_r< int, mem_type, X& >(), "");
64+
static_assert( is_nt_invocable_r< int&, mem_type, X& >(), "");
65+
static_assert( is_nt_invocable_r< long, mem_type, X& >(), "");
66+
static_assert( ! is_nt_invocable_r< long&, mem_type, X& >(),
67+
"conversion fails, cannot bind long& to int");
68+
static_assert( is_nt_invocable_r< int&, mem_type, X* >(), "");
69+
70+
static_assert( ! is_nt_invocable_r< T, mem_type, X& >(),
71+
"conversion throws");
72+
static_assert( is_nt_invocable_r< NT, mem_type, X& >(), "");
73+
static_assert( ! is_nt_invocable_r< Ex, mem_type, X& >(),
74+
"conversion fails, would use explicit constructor");
6375

6476
using memfun_type = int (X::*)();
6577

66-
static_assert( ! is_nt_invocable< memfun_type >(), "");
67-
static_assert( ! is_nt_invocable< memfun_type, int >(), "");
68-
static_assert( ! is_nt_invocable< memfun_type, int& >(), "");
69-
static_assert( ! is_nt_invocable< memfun_type, X& >(), "");
70-
static_assert( ! is_nt_invocable< memfun_type, X* >(), "");
78+
static_assert( ! is_nt_invocable< memfun_type >(), "no object");
79+
static_assert( ! is_nt_invocable< memfun_type, int >(), "no object");
80+
static_assert( ! is_nt_invocable< memfun_type, int& >(), "no object");
81+
static_assert( ! is_nt_invocable< memfun_type, X& >(), "call throws");
82+
static_assert( ! is_nt_invocable< memfun_type, X* >(), "call throws");
83+
84+
static_assert( ! is_nt_invocable_r< T, memfun_type, X& >(), "call throws");
85+
static_assert( ! is_nt_invocable_r< NT, memfun_type, X& >(), "call throws");
86+
static_assert( ! is_nt_invocable_r< Ex, memfun_type, X& >(), "call throws");
7187

7288
#if __cpp_noexcept_function_type
7389
using memfun_type_nt = int (X::*)() noexcept;
7490

75-
static_assert( ! is_nt_invocable< memfun_type_nt >(), "");
76-
static_assert( ! is_nt_invocable< memfun_type_nt, int >(), "");
77-
static_assert( ! is_nt_invocable< memfun_type_nt, int& >(), "");
91+
static_assert( ! is_nt_invocable< memfun_type_nt >(), "no object");
92+
static_assert( ! is_nt_invocable< memfun_type_nt, int >(), "no object");
93+
static_assert( ! is_nt_invocable< memfun_type_nt, int& >(), "no object");
7894
static_assert( is_nt_invocable< memfun_type_nt, X& >(), "");
7995
static_assert( is_nt_invocable< memfun_type_nt, X* >(), "");
96+
97+
static_assert( ! is_nt_invocable_r< T, memfun_type_nt, X& >(),
98+
"conversion throws");
99+
static_assert( is_nt_invocable_r< NT, memfun_type_nt, X& >(), "");
100+
static_assert( ! is_nt_invocable_r< Ex, memfun_type_nt, X& >(),
101+
"conversion fails, would use explicit constructor");
80102
#endif
81103

82104
struct F {
@@ -89,12 +111,44 @@ void test01()
89111
};
90112
using CF = const F;
91113

92-
static_assert( ! is_nt_invocable_r< int&, F >(), "");
93-
static_assert( is_nt_invocable_r< long&, CF >(), "");
94-
static_assert( ! is_nt_invocable_r< short&, F, int >(), "" );
95-
static_assert( is_nt_invocable_r< char&, F&, int >(), "" );
96-
static_assert( is_nt_invocable_r< char&, CF, int >(), "" );
97-
static_assert( is_nt_invocable_r< char&, CF&, int >(), "" );
98-
99-
static_assert( ! is_nt_invocable< F, int, int >(), "");
114+
static_assert( ! is_nt_invocable< F >(), "call throws");
115+
static_assert( is_nt_invocable< CF >(), "");
116+
117+
static_assert( ! is_nt_invocable_r< int&, F >(), "call throws");
118+
static_assert( is_nt_invocable_r< long&, CF >(), "");
119+
static_assert( ! is_nt_invocable_r< T, F >(), "call throws");
120+
static_assert( ! is_nt_invocable_r< NT, F >(), "call throws");
121+
static_assert( ! is_nt_invocable_r< Ex, F >(), "call throws");
122+
static_assert( ! is_nt_invocable_r< T, CF >(), "conversion throws");
123+
static_assert( is_nt_invocable_r< NT, CF >(), "" );
124+
static_assert( ! is_nt_invocable_r< Ex, CF >(), "conversion fails");
125+
126+
static_assert( ! is_nt_invocable< F, int >(), "call throws");
127+
static_assert( is_nt_invocable< F&, int >(), "");
128+
129+
static_assert( ! is_nt_invocable_r< short&, F, int >(),
130+
"call throws" );
131+
static_assert( is_nt_invocable_r< char&, F&, int >(), "");
132+
static_assert( ! is_nt_invocable_r< T, F&, int >(),
133+
"conversion throws");
134+
static_assert( is_nt_invocable_r< NT, F&, int >(), "");
135+
static_assert( ! is_nt_invocable_r< Ex, F&, int >(),
136+
"conversion fails, would use explicit constructor");
137+
138+
static_assert( is_nt_invocable< CF, int >(), "");
139+
static_assert( is_nt_invocable< CF&, int >(), "");
140+
141+
static_assert( is_nt_invocable_r< char&, CF, int >(), "");
142+
static_assert( is_nt_invocable_r< char&, CF&, int >(), "");
143+
144+
static_assert( ! is_nt_invocable_r< T, CF&, int >(),
145+
"conversion throws");
146+
static_assert( is_nt_invocable_r< NT, CF&, int >(), "");
147+
static_assert( ! is_nt_invocable_r< Ex, CF&, int >(),
148+
"conversion fails, would use explicit constructor");
149+
150+
static_assert( ! is_nt_invocable< F, int, int >(),
151+
"would call private member");
152+
static_assert( ! is_nt_invocable_r<void, F, int, int >(),
153+
"would call private member");
100154
}

libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ template<typename... T>
2727
constexpr bool is_nt_invocable_conv(std::true_type)
2828
{
2929
using result_type = typename std::__invoke_result<T...>::type;
30-
return std::is_void<R>::value || std::is_convertible<result_type, R>::value;
30+
return std::is_void<R>::value
31+
|| (std::is_convertible<result_type, R>::value
32+
&& std::is_nothrow_constructible<R, result_type>::value);
3133
}
3234

3335
template<typename R, typename... T>

0 commit comments

Comments
 (0)