[PATCH] Fix exception-specifications for std::_Not_fn

Jonathan Wakely jwakely@redhat.com
Thu Oct 13 10:19:00 GMT 2016


The exception specifications for _Not_fn::operator() should consider
whether operator! on the result can throw.

	* 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.

Tested powerpc64le-linux, committed to trunk.

-------------- next part --------------
commit 333bf1f483cb3ba215fe959867310c7d2dd99e58
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 13 10:34:43 2016 +0100

    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.

diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 6a45314..58134b7 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -2140,6 +2140,16 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
   template<typename _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:
       template<typename _Fn2>
 	_Not_fn(_Fn2&& __fn, int)
@@ -2152,21 +2162,21 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
       template<typename... _Args>
 	auto
 	operator()(_Args&&... __args) &
-	noexcept(__is_nothrow_callable<_Fn&(_Args&&...)>::value)
+	noexcept(__noexcept_cond<_Fn&, _Args&&...>::value)
 	-> decltype(!std::declval<result_of_t<_Fn&(_Args&&...)>>())
 	{ return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
 
       template<typename... _Args>
 	auto
 	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&&...)>>())
 	{ return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
 
       template<typename... _Args>
 	auto
 	operator()(_Args&&... __args) &&
-	noexcept(__is_nothrow_callable<_Fn&&(_Args&&...)>::value)
+	noexcept(__noexcept_cond<_Fn&&, _Args&&...>::value)
 	-> decltype(!std::declval<result_of_t<_Fn&&(_Args&&...)>>())
 	{
 	  return !std::__invoke(std::move(_M_fn),
@@ -2176,7 +2186,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
       template<typename... _Args>
 	auto
 	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&&...)>>())
 	{
 	  return !std::__invoke(std::move(_M_fn),
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/1.cc b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/1.cc
new file mode 100644
index 0000000..246b962
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/1.cc
@@ -0,0 +1,133 @@
+// Copyright (C) 2014-2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::not_fn;
+
+int func(int, char) { return 0; }
+
+struct F
+{
+  bool operator()() { return false; }
+  bool operator()() const { return true; }
+  bool operator()(int) { return false; }
+};
+
+void
+test01()
+{
+  auto f1 = not_fn(func);
+  VERIFY( f1(1, '2') == true );
+
+  auto f2 = not_fn( [] { return true; } );
+  VERIFY( f2() == false );
+
+  auto f3 = not_fn( F{} );
+  VERIFY( f3() == true );
+  VERIFY( f3(1) == true );
+  const auto f4 = f3;
+  VERIFY( f4() == false );
+}
+
+template<typename F, typename Arg>
+auto foo(F f, Arg arg) -> decltype(not_fn(f)(arg)) { return not_fn(f)(arg); }
+
+template<typename F, typename Arg>
+auto foo(F f, Arg arg) -> decltype(not_fn(f)()) { return not_fn(f)(); }
+
+struct negator
+{
+    bool operator()(int) const { return false; }
+    void operator()() const {}
+};
+
+void
+test02()
+{
+  foo(negator{}, 1); // PR libstdc++/66998
+}
+
+void
+test03()
+{
+  struct X { bool b; };
+  X x{ false };
+  VERIFY( not_fn(&X::b)(x) );
+}
+
+void
+test04()
+{
+  struct abstract { virtual void f() = 0; };
+  struct derived : abstract { void f() { } };
+  struct F { bool operator()(abstract&) { return false; } };
+  F f;
+  derived d;
+  VERIFY( not_fn(f)(d) );
+}
+
+void
+test05()
+{
+  auto nf = std::not_fn([] { return false; });
+  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
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+  test06();
+  test07();
+}
diff --git a/libstdc++-v3/testsuite/20_util/not_fn/1.cc b/libstdc++-v3/testsuite/20_util/not_fn/1.cc
deleted file mode 100644
index 233a6d3..0000000
--- a/libstdc++-v3/testsuite/20_util/not_fn/1.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (C) 2014-2016 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING3.  If not see
-// <http://www.gnu.org/licenses/>.
-
-// { dg-options "-std=gnu++17" }
-
-#include <functional>
-#include <testsuite_hooks.h>
-
-using std::not_fn;
-
-int func(int, char) { return 0; }
-
-struct F
-{
-  bool operator()() { return false; }
-  bool operator()() const { return true; }
-  bool operator()(int) { return false; }
-};
-
-void
-test01()
-{
-  auto f1 = not_fn(func);
-  VERIFY( f1(1, '2') == true );
-
-  auto f2 = not_fn( [] { return true; } );
-  VERIFY( f2() == false );
-
-  auto f3 = not_fn( F{} );
-  VERIFY( f3() == true );
-  VERIFY( f3(1) == true );
-  const auto f4 = f3;
-  VERIFY( f4() == false );
-}
-
-template<typename F, typename Arg>
-auto foo(F f, Arg arg) -> decltype(not_fn(f)(arg)) { return not_fn(f)(arg); }
-
-template<typename F, typename Arg>
-auto foo(F f, Arg arg) -> decltype(not_fn(f)()) { return not_fn(f)(); }
-
-struct negator
-{
-    bool operator()(int) const { return false; }
-    void operator()() const {}
-};
-
-void
-test02()
-{
-  foo(negator{}, 1); // PR libstdc++/66998
-}
-
-void
-test03()
-{
-  struct X { bool b; };
-  X x{ false };
-  VERIFY( not_fn(&X::b)(x) );
-}
-
-void
-test04()
-{
-  struct abstract { virtual void f() = 0; };
-  struct derived : abstract { void f() { } };
-  struct F { bool operator()(abstract&) { return false; } };
-  F f;
-  derived d;
-  VERIFY( not_fn(f)(d) );
-}
-
-void
-test05()
-{
-  auto nf = std::not_fn([] { return false; });
-  auto copy(nf); // PR libstdc++/70564
-}
-
-int
-main()
-{
-  test01();
-  test02();
-  test03();
-  test04();
-  test05();
-}


More information about the Gcc-patches mailing list