]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix exception-specifications for std::_Not_fn
authorJonathan Wakely <jwakely@redhat.com>
Thu, 13 Oct 2016 10:19:24 +0000 (11:19 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 13 Oct 2016 10:19:24 +0000 (11:19 +0100)
* 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

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/functional
libstdc++-v3/testsuite/20_util/function_objects/not_fn/1.cc [moved from libstdc++-v3/testsuite/20_util/not_fn/1.cc with 77% similarity]

index 5ee2626ed65ef074ca125d5fe861f19a44f5e70f..ffb78ea2f919152c5500633c31adda78b011986a 100644 (file)
@@ -1,5 +1,11 @@
 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/std/functional (invoke): Likewise.
        * testsuite/20_util/function_objects/invoke/1.cc: New test.
index 6a4531477382e1d8f5ca146622a2f701d062d9a4..58134b7a0e5eeb864417fd2709df3566a09f5cb5 100644 (file)
@@ -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),
similarity index 77%
rename from libstdc++-v3/testsuite/20_util/not_fn/1.cc
rename to libstdc++-v3/testsuite/20_util/function_objects/not_fn/1.cc
index 233a6d314aaf28a3b4365bba2a88202729b5ff89..246b962bc46f93b74649db0b6ff5a1d088658588 100644 (file)
@@ -91,6 +91,35 @@ test05()
   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()
 {
@@ -99,4 +128,6 @@ main()
   test03();
   test04();
   test05();
+  test06();
+  test07();
 }