From d49b3426947aa1064d8d224619da66daaf4bfb8a Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 3 May 2018 15:08:36 +0100 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 10 ++++ libstdc++-v3/include/std/thread | 52 +++++++++++-------- .../testsuite/30_threads/thread/cons/84535.cc | 31 +++++++++++ 3 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 libstdc++-v3/testsuite/30_threads/thread/cons/84535.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9356e47ec98..41760444d59 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,15 @@ 2018-05-03 Jonathan Wakely + 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 1cabd6ae0e6..61861b58520 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 + using __not_same = __not_, thread>>; - thread(thread&& __t) noexcept - { swap(__t); } + public: + thread() noexcept = default; - template + template>> explicit thread(_Callable&& __f, _Args&&... __args) { + static_assert( __is_invocable::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(&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 - static __tuple_element_t<_Index, _Tuple>&& - _S_declval(); + template + struct __result; + template + struct __result> + : __invoke_result<_Fn, _Args...> + { }; template - 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::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::value>::__type; + return _M_invoke(_Indices()); + } }; template - using __decayed_tuple = tuple::type...>; + using __decayed_tuple = tuple::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 00000000000..c96929b6873 --- /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 +// . + +#include + +using std::is_constructible; +using std::thread; + +// PR libstdc++/84535 +static_assert(!is_constructible::value, ""); +static_assert(!is_constructible::value, ""); +static_assert(!is_constructible::value, ""); +static_assert(!is_constructible::value, ""); -- 2.30.2