diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2018-05-03 15:08:36 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2018-05-03 15:08:36 +0100 |
commit | d49b3426947aa1064d8d224619da66daaf4bfb8a (patch) | |
tree | f9749ffd105f6da70ff696ec7a8837ce916d1670 | |
parent | 63f122152f8f6f02cfd19677167f05428c2e7f9a (diff) | |
download | gcc-d49b3426947aa1064d8d224619da66daaf4bfb8a.zip gcc-d49b3426947aa1064d8d224619da66daaf4bfb8a.tar.gz gcc-d49b3426947aa1064d8d224619da66daaf4bfb8a.tar.bz2 |
PR libstdc++/84535 constrain std::thread constructor
The standard requires that the std::thread constructor is constrained so
it can't be called with a first argument of type std::thread. The
current implementation only meets that requirement if the constructor is
called with one argument, by using deleted overloads. This uses an
enable_if constraint to enforce the requirement for any number of
arguments.
Also add a static assertion to give a more readable error for invalid
arguments that cannot be invoked. Also simplify _Invoker to reduce the
error cascade for ill-formed instantiations with non-invocable
arguments.
PR libstdc++/84535
* include/std/thread (thread::__not_same): New SFINAE helper.
(thread::thread(_Callable&&, _Args&&...)): Add SFINAE constraint that
first argument is not a std::thread. Add static assertion to check
INVOKE expression is valid.
(thread::thread(thread&), thread::thread(const thread&&)): Remove.
(thread::_Invoke::_M_invoke, thread::_Invoke::operator()): Use
__invoke_result for return types and remove exception specifications.
* testsuite/30_threads/thread/cons/84535.cc: New.
From-SVN: r259893
-rw-r--r-- | libstdc++-v3/ChangeLog | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/std/thread | 52 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/30_threads/thread/cons/84535.cc | 31 |
3 files changed, 71 insertions, 22 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9356e47..4176044 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,15 @@ 2018-05-03 Jonathan Wakely <jwakely@redhat.com> + PR libstdc++/84535 + * include/std/thread (thread::__not_same): New SFINAE helper. + (thread::thread(_Callable&&, _Args&&...)): Add SFINAE constraint that + first argument is not a std::thread. Add static assertion to check + INVOKE expression is valid. + (thread::thread(thread&), thread::thread(const thread&&)): Remove. + (thread::_Invoke::_M_invoke, thread::_Invoke::operator()): Use + __invoke_result for return types and remove exception specifications. + * testsuite/30_threads/thread/cons/84535.cc: New. + * include/std/future (__async_result_of): Use __invoke_result instead of result_of. diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index 1cabd6a..61861b5 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -102,21 +102,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: id _M_id; - public: - thread() noexcept = default; // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2097. packaged_task constructors should be constrained - thread(thread&) = delete; - thread(const thread&) = delete; - thread(const thread&&) = delete; + template<typename _Tp> + using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>; - thread(thread&& __t) noexcept - { swap(__t); } + public: + thread() noexcept = default; - template<typename _Callable, typename... _Args> + template<typename _Callable, typename... _Args, + typename = _Require<__not_same<_Callable>>> explicit thread(_Callable&& __f, _Args&&... __args) { + static_assert( __is_invocable<typename decay<_Callable>::type, + typename decay<_Args>::type...>::value, + "std::thread arguments must be invocable after conversion to rvalues" + ); + #ifdef GTHR_ACTIVE_PROXY // Create a reference to pthread_create, not just the gthr weak symbol. auto __depend = reinterpret_cast<void(*)()>(&pthread_create); @@ -135,6 +138,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::terminate(); } + thread(const thread&) = delete; + + thread(thread&& __t) noexcept + { swap(__t); } + thread& operator=(const thread&) = delete; thread& operator=(thread&& __t) noexcept @@ -222,29 +230,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _Tuple _M_t; - template<size_t _Index> - static __tuple_element_t<_Index, _Tuple>&& - _S_declval(); + template<typename> + struct __result; + template<typename _Fn, typename... _Args> + struct __result<tuple<_Fn, _Args...>> + : __invoke_result<_Fn, _Args...> + { }; template<size_t... _Ind> - auto + typename __result<_Tuple>::type _M_invoke(_Index_tuple<_Ind...>) - noexcept(noexcept(std::__invoke(_S_declval<_Ind>()...))) - -> decltype(std::__invoke(_S_declval<_Ind>()...)) { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); } - using _Indices - = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; - - auto + typename __result<_Tuple>::type operator()() - noexcept(noexcept(std::declval<_Invoker&>()._M_invoke(_Indices()))) - -> decltype(std::declval<_Invoker&>()._M_invoke(_Indices())) - { return _M_invoke(_Indices()); } + { + using _Indices + = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; + return _M_invoke(_Indices()); + } }; template<typename... _Tp> - using __decayed_tuple = tuple<typename std::decay<_Tp>::type...>; + using __decayed_tuple = tuple<typename decay<_Tp>::type...>; public: // Returns a call wrapper that stores diff --git a/libstdc++-v3/testsuite/30_threads/thread/cons/84535.cc b/libstdc++-v3/testsuite/30_threads/thread/cons/84535.cc new file mode 100644 index 0000000..c96929b --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/thread/cons/84535.cc @@ -0,0 +1,31 @@ +// { dg-do compile { target c++11 } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } + +// Copyright (C) 2018 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/>. + +#include <thread> + +using std::is_constructible; +using std::thread; + +// PR libstdc++/84535 +static_assert(!is_constructible<thread, thread, int>::value, ""); +static_assert(!is_constructible<thread, thread&, int>::value, ""); +static_assert(!is_constructible<thread, const thread&, int>::value, ""); +static_assert(!is_constructible<thread, const thread&&, int>::value, ""); |