aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2017-07-11 12:38:35 +0000
committerJonathan Wakely <jwakely@redhat.com>2017-07-11 12:38:35 +0000
commit3c97cd1449b8c7f4ef752207274b210bf0337de6 (patch)
tree1cbdc4778faaa9c2f171c69961bd0eea921e0a86
parenta7b7f6b92e3f3231c6c57851bc38d58f60574232 (diff)
PR libstdc++/80316 make promise::set_value throw no_state error
Backport from mainline 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. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcc-6-branch@250131 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libstdc++-v3/ChangeLog26
-rw-r--r--libstdc++-v3/include/std/future59
-rw-r--r--libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc167
-rw-r--r--libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc49
-rw-r--r--libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc181
-rw-r--r--libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc292
6 files changed, 745 insertions, 29 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 81c1d7f9f43..fbabb99bb90 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,29 @@
+2017-07-11 Jonathan Wakely <jwakely@redhat.com>
+
+ Backport from mainline
+ 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.
+
2017-07-04 Release Manager
* GCC 6.4.0 released.
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index 80b7b06a45f..830494f1904 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -462,7 +462,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);
}
@@ -477,7 +476,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);
}
@@ -485,6 +483,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
@@ -494,7 +504,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);
}
@@ -507,6 +516,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) };
}
@@ -514,9 +524,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)
@@ -1014,6 +1033,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;
@@ -1124,6 +1144,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;
@@ -1213,6 +1234,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;
@@ -1273,14 +1295,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)
@@ -1290,30 +1315,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
index 00000000000..9429a9958d2
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
@@ -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();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
index b753c24ef5e..76343f7f696 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
@@ -23,6 +23,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>
@@ -50,8 +51,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;
}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
index d9850ca9405..951c8e16a68 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
@@ -23,10 +23,13 @@
// 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;
@@ -85,9 +88,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;
}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
index 9c308c5e69e..2a3f9b89ce3 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
@@ -23,10 +23,13 @@
// 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;
@@ -81,9 +84,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;
}