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.
// 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);
}
// 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);
}
_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
// 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);
}
static _Setter<_Res, _Arg&&>
__setter(promise<_Res>* __prom, _Arg&& __arg)
{
+ _S_check(__prom->_M_future);
return _Setter<_Res, _Arg&&>{ __prom, std::__addressof(__arg) };
}
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)
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;
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;
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;
{ 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)
}
};
- // 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
{
--- /dev/null
+// { 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();
+}
// 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>
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;
}
// 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;
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;
}
// 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;
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;
}