PR libstdc++/80316 make promise::set_value throw no_state error
authorJonathan Wakely <jwakely@redhat.com>
Fri, 21 Apr 2017 14:49:19 +0000 (15:49 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 21 Apr 2017 14:49:19 +0000 (15:49 +0100)
PR libstdc++/80316
* include/std/future (_State_baseV2::_Setter::operator()): Remove
_S_check calls that are done after the pointer to the shared state is
already dereferenced.
(_State_baseV2::_Setter<_Res, void>): Define specialization for void
as partial specialization so it can be defined within the definition
of _State_baseV2.
(_State_baseV2::__setter): Call _S_check.
(_State_baseV2::__setter(promise<void>*)): Add overload for use by
promise<void>::set_value and promise<void>::set_value_at_thread_exit.
(promise<T>, promise<T&>, promise<void>): Make _State a friend.
(_State_baseV2::_Setter<void, void>): Remove explicit specialization.
(promise<void>::set_value, promise<void>::set_value_at_thread_exit):
Use new __setter overload.
* testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
* testsuite/30_threads/promise/members/set_exception.cc: Test
promise<T&> and promise<void> specializations.
* testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
Test for no_state error condition.
* testsuite/30_threads/promise/members/set_value2.cc: Likewise.

From-SVN: r247064

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/future
libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc

index 2e587737e8f0dff5a7c890263b33e82fa753b2cb..bd43faa6c6d2ad502d258e2a85e8683723d71e6c 100644 (file)
@@ -1,5 +1,26 @@
 2017-04-21  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/80316
+       * include/std/future (_State_baseV2::_Setter::operator()): Remove
+       _S_check calls that are done after the pointer to the shared state is
+       already dereferenced.
+       (_State_baseV2::_Setter<_Res, void>): Define specialization for void
+       as partial specialization so it can be defined within the definition
+       of _State_baseV2.
+       (_State_baseV2::__setter): Call _S_check.
+       (_State_baseV2::__setter(promise<void>*)): Add overload for use by
+       promise<void>::set_value and promise<void>::set_value_at_thread_exit.
+       (promise<T>, promise<T&>, promise<void>): Make _State a friend.
+       (_State_baseV2::_Setter<void, void>): Remove explicit specialization.
+       (promise<void>::set_value, promise<void>::set_value_at_thread_exit):
+       Use new __setter overload.
+       * testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
+       * testsuite/30_threads/promise/members/set_exception.cc: Test
+       promise<T&> and promise<void> specializations.
+       * testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
+       Test for no_state error condition.
+       * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
+
        * include/backward/auto_ptr.h: Ignore deprecated warnings from use
        of auto_ptr.
        * include/bits/shared_ptr.h: Likewise.
index cb53561472ddbb0d8138f945a62df16666254b62..73d5a60a9183c32edfa5d9adf2e9ac372075596a 100644 (file)
@@ -471,7 +471,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          // Used by std::promise to copy construct the result.
           typename promise<_Res>::_Ptr_type operator()() const
           {
-            _State_baseV2::_S_check(_M_promise->_M_future);
             _M_promise->_M_storage->_M_set(*_M_arg);
             return std::move(_M_promise->_M_storage);
           }
@@ -486,7 +485,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          // Used by std::promise to move construct the result.
           typename promise<_Res>::_Ptr_type operator()() const
           {
-            _State_baseV2::_S_check(_M_promise->_M_future);
             _M_promise->_M_storage->_M_set(std::move(*_M_arg));
             return std::move(_M_promise->_M_storage);
           }
@@ -494,6 +492,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           _Res*             _M_arg;
         };
 
+      // set void
+      template<typename _Res>
+       struct _Setter<_Res, void>
+       {
+         static_assert(is_void<_Res>::value, "Only used for promise<void>");
+
+         typename promise<_Res>::_Ptr_type operator()() const
+         { return std::move(_M_promise->_M_storage); }
+
+         promise<_Res>*    _M_promise;
+       };
+
       struct __exception_ptr_tag { };
 
       // set exceptions
@@ -503,7 +513,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          // Used by std::promise to store an exception as the result.
           typename promise<_Res>::_Ptr_type operator()() const
           {
-            _State_baseV2::_S_check(_M_promise->_M_future);
             _M_promise->_M_storage->_M_error = *_M_ex;
             return std::move(_M_promise->_M_storage);
           }
@@ -516,6 +525,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         static _Setter<_Res, _Arg&&>
         __setter(promise<_Res>* __prom, _Arg&& __arg)
         {
+         _S_check(__prom->_M_future);
           return _Setter<_Res, _Arg&&>{ __prom, std::__addressof(__arg) };
         }
 
@@ -523,9 +533,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         static _Setter<_Res, __exception_ptr_tag>
         __setter(exception_ptr& __ex, promise<_Res>* __prom)
         {
+         _S_check(__prom->_M_future);
           return _Setter<_Res, __exception_ptr_tag>{ __prom, &__ex };
         }
 
+      template<typename _Res>
+       static _Setter<_Res, void>
+       __setter(promise<_Res>* __prom)
+       {
+         _S_check(__prom->_M_future);
+         return _Setter<_Res, void>{ __prom };
+       }
+
       template<typename _Tp>
         static void
         _S_check(const shared_ptr<_Tp>& __p)
@@ -1027,6 +1046,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __future_base::_Result<_Res>     _Res_type;
       typedef __future_base::_Ptr<_Res_type>   _Ptr_type;
       template<typename, typename> friend class _State::_Setter;
+      friend _State;
 
       shared_ptr<_State>                        _M_future;
       _Ptr_type                                 _M_storage;
@@ -1137,6 +1157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __future_base::_Result<_Res&>    _Res_type;
       typedef __future_base::_Ptr<_Res_type>   _Ptr_type;
       template<typename, typename> friend class _State::_Setter;
+      friend _State;
 
       shared_ptr<_State>                        _M_future;
       _Ptr_type                                 _M_storage;
@@ -1226,6 +1247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __future_base::_Result<void>     _Res_type;
       typedef __future_base::_Ptr<_Res_type>   _Ptr_type;
       template<typename, typename> friend class _State::_Setter;
+      friend _State;
 
       shared_ptr<_State>                        _M_future;
       _Ptr_type                                 _M_storage;
@@ -1286,14 +1308,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return future<void>(_M_future); }
 
       // Setting the result
-      void set_value();
+      void
+      set_value()
+      { _M_future->_M_set_result(_State::__setter(this)); }
 
       void
       set_exception(exception_ptr __p)
       { _M_future->_M_set_result(_State::__setter(__p, this)); }
 
       void
-      set_value_at_thread_exit();
+      set_value_at_thread_exit()
+      { _M_future->_M_set_delayed_result(_State::__setter(this), _M_future); }
 
       void
       set_exception_at_thread_exit(exception_ptr __p)
@@ -1303,30 +1328,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
     };
 
-  // set void
-  template<>
-    struct __future_base::_State_base::_Setter<void, void>
-    {
-      promise<void>::_Ptr_type operator()() const
-      {
-        _State_base::_S_check(_M_promise->_M_future);
-        return std::move(_M_promise->_M_storage);
-      }
-
-      promise<void>*    _M_promise;
-    };
-
-  inline void
-  promise<void>::set_value()
-  { _M_future->_M_set_result(_State::_Setter<void, void>{ this }); }
-
-  inline void
-  promise<void>::set_value_at_thread_exit()
-  {
-    _M_future->_M_set_delayed_result(_State::_Setter<void, void>{this},
-                                    _M_future);
-  }
-
   template<typename _Ptr_type, typename _Fn, typename _Res>
     struct __future_base::_Task_setter
     {
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
new file mode 100644 (file)
index 0000000..9429a99
--- /dev/null
@@ -0,0 +1,167 @@
+// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-rtems* *-*-darwin* powerpc-ibm-aix* } }
+// { dg-options "-pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* powerpc-ibm-aix* } }
+// { dg-require-effective-target c++11 }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// Test set_value_at_thread_exit error conditions
+
+#include <future>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::promise<int> p1;
+  p1.set_value(1);
+  try
+  {
+    p1.set_value_at_thread_exit(2);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+
+  std::promise<int> p2(std::move(p1));
+  try
+  {
+    p1.set_value_at_thread_exit(2);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+}
+
+void test02()
+{
+  std::promise<int&> p1;
+  int i = 1;
+  p1.set_value(i);
+  try
+  {
+    p1.set_value_at_thread_exit(i);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+
+  std::promise<int&> p2(std::move(p1));
+  try
+  {
+    int i = 0;
+    p1.set_value_at_thread_exit(i);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+}
+
+void test03()
+{
+  std::promise<void> p1;
+  int i = 0;
+  p1.set_value();
+  try {
+    p1.set_value_at_thread_exit();
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+  }
+
+  std::promise<void> p2(std::move(p1));
+  try {
+    p1.set_value_at_thread_exit();
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+  try
+  {
+    p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY( e.code() == std::future_errc::no_state );
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+}
index 6ff4a348f2a8a96ed7d69666e6d303dcf3cbf554..4646e381a2fb3e7151027fe70f5e2231332562b1 100644 (file)
@@ -21,6 +21,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// Test that promise::set_exception stores an exception.
 
 #include <future>
 #include <testsuite_hooks.h>
@@ -48,8 +49,56 @@ void test01()
   VERIFY( !f1.valid() );
 }
 
+void test02()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  VERIFY( f1.valid() );
+
+  p1.set_exception(std::make_exception_ptr(0));
+
+  try
+  {
+    f1.get();
+  }
+  catch (int)
+  {
+    test = true;
+  }
+  VERIFY( test );
+  VERIFY( !f1.valid() );
+}
+
+void test03()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  VERIFY( f1.valid() );
+
+  p1.set_exception(std::make_exception_ptr(0));
+
+  try
+  {
+    f1.get();
+  }
+  catch (int)
+  {
+    test = true;
+  }
+  VERIFY( test );
+  VERIFY( !f1.valid() );
+}
+
 int main()
 {
   test01();
+  test02();
+  test03();
   return 0;
 }
index 1b1a0667860c8beb48eb47c68c0161c8cf0c73f9..dc2c4a88a9c66170016f6c441036ac75e870da56 100644 (file)
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// Test that promise::set_exception throws when required.
 
 #include <future>
 #include <testsuite_hooks.h>
 
+// Check for promise_already_satisfied error conditions.
+
 void test01()
 {
   bool test = false;
@@ -83,9 +86,187 @@ void test02()
   VERIFY( test );
 }
 
+void test03()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  p1.set_exception(std::make_exception_ptr(0));
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(1));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  try
+  {
+    f1.get();
+    test = false;
+  }
+  catch(int i)
+  {
+    VERIFY( i == 0 );
+  }
+
+  VERIFY( test );
+}
+
+void test04()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  int i = 2;
+  p1.set_value(i);
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(0));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  VERIFY( test );
+}
+
+void test05()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  p1.set_exception(std::make_exception_ptr(0));
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(1));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  try
+  {
+    f1.get();
+    test = false;
+  }
+  catch(int i)
+  {
+    VERIFY( i == 0 );
+  }
+
+  VERIFY( test );
+}
+
+void test06()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  p1.set_value();
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(0));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  VERIFY( test );
+}
+
+// Check for no_state error condition (PR libstdc++/80316)
+
+void test07()
+{
+  using namespace std;
+
+  promise<int> p1;
+  promise<int> p2(std::move(p1));
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(1));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
+void test08()
+{
+  using namespace std;
+
+  promise<int&> p1;
+  promise<int&> p2(std::move(p1));
+  try
+  {
+    int i = 0;
+    p1.set_exception(std::make_exception_ptr(1));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
+void test09()
+{
+  using namespace std;
+
+  promise<void> p1;
+  promise<void> p2(std::move(p1));
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(1));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
+  test04();
+  test05();
+  test06();
+  test07();
+  test08();
+  test09();
   return 0;
 }
index 0c4e87a253d89c32d0b5685e089f12f22436ea6b..33c8ed9ede4599adf320ef5b3fd2ac710d4cba2b 100644 (file)
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// Test that promise::set_value throws when required.
 
 #include <future>
 #include <testsuite_hooks.h>
 
+// Check for promise_already_satisfied error conditions.
+
 void test01()
 {
   bool test = false;
@@ -79,9 +82,298 @@ void test02()
   VERIFY( test );
 }
 
+void test03()
+{
+  bool test = false;
+
+  std::promise<int> p1;
+  std::future<int> f1 = p1.get_future();
+
+  p1.set_exception(std::make_exception_ptr(4));
+
+  try
+  {
+    p1.set_value(3);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  test = false;
+  try
+  {
+    f1.get();
+    VERIFY( false );
+  }
+  catch (int e)
+  {
+    VERIFY(e == 4 );
+    test = true;
+  }
+
+  VERIFY( test );
+}
+
+void test04()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  int i = 1;
+  p1.set_value(i);
+
+  try
+  {
+    p1.set_value(i);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  VERIFY( f1.get() == 1 );
+  VERIFY( test );
+}
+
+void test05()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  int i = 3;
+  p1.set_value(i);
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(4));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  VERIFY( f1.get() == 3 );
+  VERIFY( test );
+}
+
+void test06()
+{
+  bool test = false;
+
+  std::promise<int&> p1;
+  std::future<int&> f1 = p1.get_future();
+
+  p1.set_exception(std::make_exception_ptr(4));
+
+  try
+  {
+    int i = 3;
+    p1.set_value(i);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  test = false;
+  try
+  {
+    f1.get();
+    VERIFY( false );
+  }
+  catch (int e)
+  {
+    VERIFY(e == 4 );
+    test = true;
+  }
+
+  VERIFY( test );
+}
+
+void test07()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  p1.set_value();
+
+  try
+  {
+    p1.set_value();
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  f1.get();
+  VERIFY( test );
+}
+
+void test08()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  p1.set_value();
+
+  try
+  {
+    p1.set_exception(std::make_exception_ptr(4));
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  f1.get();
+  VERIFY( test );
+}
+
+void test09()
+{
+  bool test = false;
+
+  std::promise<void> p1;
+  std::future<void> f1 = p1.get_future();
+
+  p1.set_exception(std::make_exception_ptr(4));
+
+  try
+  {
+    p1.set_value();
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() ==
+        std::make_error_code(std::future_errc::promise_already_satisfied));
+    test = true;
+  }
+
+  std::chrono::milliseconds delay(1);
+  VERIFY( f1.wait_for(delay) == std::future_status::ready );
+  test = false;
+  try
+  {
+    f1.get();
+    VERIFY( false );
+  }
+  catch (int e)
+  {
+    VERIFY(e == 4 );
+    test = true;
+  }
+
+  VERIFY( test );
+}
+
+// Check for no_state error condition (PR libstdc++/80316)
+
+void test10()
+{
+  using namespace std;
+
+  promise<int> p1;
+  promise<int> p2(std::move(p1));
+  try
+  {
+    p1.set_value(1);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
+void test11()
+{
+  using namespace std;
+
+  promise<int&> p1;
+  promise<int&> p2(std::move(p1));
+  try
+  {
+    int i = 0;
+    p1.set_value(i);
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
+void test12()
+{
+  using namespace std;
+
+  promise<void> p1;
+  promise<void> p2(std::move(p1));
+  try
+  {
+    p1.set_value();
+    VERIFY( false );
+  }
+  catch (std::future_error& e)
+  {
+    VERIFY(e.code() == make_error_code(future_errc::no_state));
+  }
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
+  test04();
+  test05();
+  test06();
+  test07();
+  test08();
+  test09();
+  test10();
+  test11();
+  test12();
   return 0;
 }