Commit cc06c7f6 by Jonathan Wakely Committed by Jonathan Wakely

Fix exception-specifications for std::_Not_fn

	* include/std/functional (_Not_fn): Make exception specifications
	depend on whether negating the result can throw.
	* testsuite/20_util/not_fn/1.cc: Move to ...
	* testsuite/20_util/function_objects/not_fn/1.cc: ... here. Add tests
	for types that can throw when negated and that cannot be negated.

From-SVN: r241091
parent 27947670
2016-10-13 Jonathan Wakely <jwakely@redhat.com> 2016-10-13 Jonathan Wakely <jwakely@redhat.com>
* include/std/functional (_Not_fn): Make exception specifications
depend on whether negating the result can throw.
* testsuite/20_util/not_fn/1.cc: Move to ...
* testsuite/20_util/function_objects/not_fn/1.cc: ... here. Add tests
for types that can throw when negated and that cannot be negated.
* include/bits/invoke.h (__invoke): Fix exception-specification. * include/bits/invoke.h (__invoke): Fix exception-specification.
* include/std/functional (invoke): Likewise. * include/std/functional (invoke): Likewise.
* testsuite/20_util/function_objects/invoke/1.cc: New test. * testsuite/20_util/function_objects/invoke/1.cc: New test.
......
...@@ -2140,6 +2140,16 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) ...@@ -2140,6 +2140,16 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
template<typename _Fn> template<typename _Fn>
class _Not_fn class _Not_fn
{ {
template<typename _Tp>
using __is_nothrow_negatable
= __bool_constant<noexcept(!std::declval<_Tp>())>;
template<typename _Fn2, typename... _Args>
using __noexcept_cond = __and_<
__is_nothrow_callable<_Fn2(_Args&&...)>,
__is_nothrow_negatable<result_of_t<_Fn2(_Args&&...)>>
>;
public: public:
template<typename _Fn2> template<typename _Fn2>
_Not_fn(_Fn2&& __fn, int) _Not_fn(_Fn2&& __fn, int)
...@@ -2152,21 +2162,21 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) ...@@ -2152,21 +2162,21 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
template<typename... _Args> template<typename... _Args>
auto auto
operator()(_Args&&... __args) & operator()(_Args&&... __args) &
noexcept(__is_nothrow_callable<_Fn&(_Args&&...)>::value) noexcept(__noexcept_cond<_Fn&, _Args&&...>::value)
-> decltype(!std::declval<result_of_t<_Fn&(_Args&&...)>>()) -> decltype(!std::declval<result_of_t<_Fn&(_Args&&...)>>())
{ return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
template<typename... _Args> template<typename... _Args>
auto auto
operator()(_Args&&... __args) const & operator()(_Args&&... __args) const &
noexcept(__is_nothrow_callable<const _Fn&(_Args&&...)>::value) noexcept(__noexcept_cond<const _Fn&, _Args&&...>::value)
-> decltype(!std::declval<result_of_t<const _Fn&(_Args&&...)>>()) -> decltype(!std::declval<result_of_t<const _Fn&(_Args&&...)>>())
{ return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
template<typename... _Args> template<typename... _Args>
auto auto
operator()(_Args&&... __args) && operator()(_Args&&... __args) &&
noexcept(__is_nothrow_callable<_Fn&&(_Args&&...)>::value) noexcept(__noexcept_cond<_Fn&&, _Args&&...>::value)
-> decltype(!std::declval<result_of_t<_Fn&&(_Args&&...)>>()) -> decltype(!std::declval<result_of_t<_Fn&&(_Args&&...)>>())
{ {
return !std::__invoke(std::move(_M_fn), return !std::__invoke(std::move(_M_fn),
...@@ -2176,7 +2186,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) ...@@ -2176,7 +2186,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
template<typename... _Args> template<typename... _Args>
auto auto
operator()(_Args&&... __args) const && operator()(_Args&&... __args) const &&
noexcept(__is_nothrow_callable<const _Fn&&(_Args&&...)>::value) noexcept(__noexcept_cond<const _Fn&&, _Args&&...>::value)
-> decltype(!std::declval<result_of_t<const _Fn&&(_Args&&...)>>()) -> decltype(!std::declval<result_of_t<const _Fn&&(_Args&&...)>>())
{ {
return !std::__invoke(std::move(_M_fn), return !std::__invoke(std::move(_M_fn),
......
...@@ -91,6 +91,35 @@ test05() ...@@ -91,6 +91,35 @@ test05()
auto copy(nf); // PR libstdc++/70564 auto copy(nf); // PR libstdc++/70564
} }
void
test06()
{
struct Boolean {
Boolean operator!() noexcept(false) { return *this; }
};
struct F {
Boolean operator()() { return {}; }
};
F f;
auto notf = std::not_fn(f);
using NotF = decltype(notf);
static_assert( std::is_callable<NotF()>::value, "cannot negate" );
static_assert( !noexcept(notf()), "conversion to bool affects noexcept" );
}
void
test07()
{
struct NonNegatable { };
struct F {
NonNegatable operator()() { return {}; }
};
F f;
auto notf = std::not_fn(f);
using NotF = decltype(notf);
static_assert( !std::is_callable<NotF()>::value, "cannot negate" );
}
int int
main() main()
{ {
...@@ -99,4 +128,6 @@ main() ...@@ -99,4 +128,6 @@ main()
test03(); test03();
test04(); test04();
test05(); test05();
test06();
test07();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment