Commit 946ecd6a by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/80316 make promise::set_value throw no_state error

	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
parent a2c0a194
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.
......
......@@ -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
{
......
// { 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();
}
......@@ -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;
}
......@@ -21,10 +21,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;
......@@ -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;
}
......@@ -21,10 +21,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;
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment