libstdc++: Fix for explicit copy ctors in <thread> and <future> [PR106695]

When I changed std::thread and std::async to avoid unnecessary move
construction of temporaries, I introduced a regression where types with
an explicit copy constructor could not be passed to std::thread or
std::async. The fix is to add a constructor instead of using aggregate
initialization of an unnamed temporary.

libstdc++-v3/ChangeLog:

	PR libstdc++/106695
	* include/bits/std_thread.h (thread::_State_impl): Forward
	individual arguments to _Invoker constructor.
	(thread::_Invoker): Add constructor. Delete copies.
	* include/std/future (__future_base::_Deferred_state): Forward
	individual arguments to _Invoker constructor.
	(__future_base::_Async_state_impl): Likewise.
	* testsuite/30_threads/async/106695.cc: New test.
	* testsuite/30_threads/thread/106695.cc: New test.
This commit is contained in:
Jonathan Wakely 2022-08-22 15:42:17 +01:00
parent 1b09eea33f
commit 5abe065755
4 changed files with 59 additions and 3 deletions

View file

@ -227,7 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
_State_impl(_Args&&... __args)
: _M_func{{std::forward<_Args>(__args)...}}
: _M_func(std::forward<_Args>(__args)...)
{ }
void
@ -261,6 +261,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tuple>
struct _Invoker
{
template<typename... _Args>
explicit
_Invoker(_Args&&... __args)
: _M_t(std::forward<_Args>(__args)...)
{ }
_Tuple _M_t;
template<typename>

View file

@ -1681,7 +1681,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
explicit
_Deferred_state(_Args&&... __args)
: _M_result(new _Result<_Res>()),
_M_fn{{std::forward<_Args>(__args)...}}
_M_fn(std::forward<_Args>(__args)...)
{ }
private:
@ -1748,7 +1748,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
explicit
_Async_state_impl(_Args&&... __args)
: _M_result(new _Result<_Res>()),
_M_fn{{std::forward<_Args>(__args)...}}
_M_fn(std::forward<_Args>(__args)...)
{
_M_thread = std::thread{&_Async_state_impl::_M_run, this};
}

View file

@ -0,0 +1,29 @@
// { dg-do compile { target c++11 } }
// { dg-require-gthreads "" }
// PR libstdc++/106695
// Explicit copy constructor does not work for a parameter passed via std::async
#include <future>
struct A {
A() = default;
explicit A(const A&) = default;
};
void func(const A&) { }
void
test_async()
{
(void) std::async(std::launch::async, func, A{});
(void) std::async(std::launch::deferred, func, A{});
(void) std::async(func, A{});
}
void
test_task()
{
std::packaged_task<void(const A&)> task(func);
task(A{});
}

View file

@ -0,0 +1,21 @@
// { dg-do compile { target c++11 } }
// { dg-require-gthreads "" }
// PR libstdc++/106695
// Explicit copy constructor does not work for a parameter passed via std::async
#include <thread>
struct A {
A() = default;
explicit A(const A&) = default;
};
void func(const A&) { }
void
test_thread()
{
std::thread t(func, A{});
t.join();
}