aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libstdc++-v3/include/std/future9
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc1
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc38
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);