diff options
3 files changed, 47 insertions, 1 deletions
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index 2a855f2..b7ab233 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1567,7 +1567,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION packaged_task(_Fn&& __fn) : _M_state( __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn))) - { } + { +#ifdef __cpp_lib_is_invocable // C++ >= 17 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4154. The Mandates for std::packaged_task's constructor + // from a callable entity should consider decaying + static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>); +#endif + } #if __cplusplus < 201703L // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc index 225b65f..51c6ade 100644 --- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc @@ -10,3 +10,4 @@ std::packaged_task<const int&()> task(f); // { dg-error "reference to temporary" "" { target { c++14_down } } 0 } // { dg-error "no matching function" "" { target c++17 } 0 } // { dg-error "enable_if" "" { target c++17 } 0 } +// { dg-error "static assertion failed" "" { target c++17 } 0 } diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc new file mode 100644 index 0000000..6ba1bb1 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc @@ -0,0 +1,38 @@ +// { dg-do compile { target c++11 } } + +// LWG 4154. The Mandates for std::packaged_task's constructor from +// a callable entity should consider decaying + +#include <future> + +struct F { + void operator()() & = delete; + void operator()() const & { } +}; + +// Mandates: is_invocable_r_v<R, decay_t<F>&, ArgTypes...> is true. +const F f; +std::packaged_task<void()> p(f); // { dg-error "here" "" { target c++17 } } +// { dg-error "static assertion failed" "" { target c++17 } 0 } +// { dg-error "invoke_r" "" { target *-*-* } 0 } +// { dg-prune-output "enable_if<false" } + +// Only callable as rvalue +struct Frv { + int* operator()() && { return 0; } +}; +std::packaged_task<int*()> p2(Frv{}); // { dg-error "here" "" { target c++17 } } + +// Only callable as non-const lvalue +struct Fnc { + void operator()() const & = delete; + void operator()() & { } +}; + +// In C++11/14/17/20 std::packaged_task::packaged_task<F>(F&&) incorrectly +// required that the callable passed to the constructor can be invoked. +// If the type of the parameter is const F& we might not be able to invoke +// the parameter, but that's OK because we store and invoke a non-const F. +// So this should work without errors: +const Fnc fnc; +std::packaged_task<void()> p3(fnc); |