aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Sandoe <iain@sandoe.co.uk>2020-06-20 14:01:21 +0100
committerIain Sandoe <iain@sandoe.co.uk>2020-06-20 16:12:32 +0100
commit445d8da5fbd10e32f8ea470bd9ac02faba8fd718 (patch)
tree9734fac4bb1b2cfac7648efd5ef69241a9d66ddd /gcc
parent57b4daf8dc4ed7b669cc70638866ddb00f5b7746 (diff)
downloadgcc-445d8da5fbd10e32f8ea470bd9ac02faba8fd718.zip
gcc-445d8da5fbd10e32f8ea470bd9ac02faba8fd718.tar.gz
gcc-445d8da5fbd10e32f8ea470bd9ac02faba8fd718.tar.bz2
coroutines: Update handling and failure for g-r-o-o-a-f [PR95505]
The actual issue is that (in the testcase) std::nothrow is not available. So update the handling of the get-return-on-alloc-fail to include the possibility that std::nothrow might not be available. gcc/cp/ChangeLog: PR c++/95505 * coroutines.cc (morph_fn_to_coro): Update handling of get-return-object-on-allocation-fail and diagnose missing std::nothrow. gcc/testsuite/ChangeLog: PR c++/95505 * g++.dg/coroutines/pr95505.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/coroutines.cc51
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr95505.C26
2 files changed, 51 insertions, 26 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 11fca99..3aaa3d4 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -3913,30 +3913,25 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree grooaf = NULL_TREE;
tree dummy_promise = build_dummy_object (get_coroutine_promise_type (orig));
- /* We don't require this, so lookup_promise_method can return NULL... */
+ /* We don't require this, so lookup_promise_method can return NULL,
+ but, if the lookup succeeds, then the function must be usable. */
if (grooaf_meth && BASELINK_P (grooaf_meth))
- {
- /* ... but, if the lookup succeeds, then the function must be
- usable.
- build_new_method_call () wants a valid pointer to (an empty) args
- list in this case. */
- vec<tree, va_gc> *args = make_tree_vector ();
- grooaf = build_new_method_call (dummy_promise, grooaf_meth, &args,
- NULL_TREE, LOOKUP_NORMAL, NULL,
- tf_warning_or_error);
- release_tree_vector (args);
- }
+ grooaf = build_new_method_call (dummy_promise, grooaf_meth, NULL,
+ NULL_TREE, LOOKUP_NORMAL, NULL,
+ tf_warning_or_error);
/* Allocate the frame, this has several possibilities:
[dcl.fct.def.coroutine] / 9 (part 1)
The allocation function’s name is looked up in the scope of the promise
type. It's not a failure for it to be absent see part 4, below. */
+
tree nwname = ovl_op_identifier (false, NEW_EXPR);
- tree fns = lookup_promise_method (orig, nwname, fn_start,
- /*musthave=*/false);
tree new_fn = NULL_TREE;
- if (fns && BASELINK_P (fns))
+
+ if (TYPE_HAS_NEW_OPERATOR (promise_type))
{
+ tree fns = lookup_promise_method (orig, nwname, fn_start,
+ /*musthave=*/true);
/* [dcl.fct.def.coroutine] / 9 (part 2)
If the lookup finds an allocation function in the scope of the promise
type, overload resolution is performed on a function call created by
@@ -3966,30 +3961,29 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
vec_safe_push (args, arg);
}
- /* We might need to check that the provided function is nothrow. */
+ /* Note the function selected; we test to see if it's NOTHROW. */
tree func;
- /* Failure is OK for the first attempt. */
+ /* Failure is not an error for this attempt. */
new_fn = build_new_method_call (dummy_promise, fns, &args, NULL,
LOOKUP_NORMAL, &func, tf_none);
release_tree_vector (args);
- if (!new_fn || new_fn == error_mark_node)
+ if (new_fn == error_mark_node)
{
/* [dcl.fct.def.coroutine] / 9 (part 3)
If no viable function is found, overload resolution is performed
again on a function call created by passing just the amount of
space required as an argument of type std::size_t. */
- args = make_tree_vector ();
- vec_safe_push (args, resizeable); /* Space needed. */
+ args = make_tree_vector_single (resizeable); /* Space needed. */
new_fn = build_new_method_call (dummy_promise, fns, &args,
NULL_TREE, LOOKUP_NORMAL, &func,
tf_none);
release_tree_vector (args);
}
- /* However, if the initial lookup succeeded, then one of these two
- options must be available. */
- if (!new_fn || new_fn == error_mark_node)
+ /* However, if the promise provides an operator new, then one of these
+ two options must be available. */
+ if (new_fn == error_mark_node)
{
error_at (fn_start, "%qE is provided by %qT but is not usable with"
" the function signature %qD", nwname, promise_type, orig);
@@ -3999,7 +3993,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
error_at (fn_start, "%qE is provided by %qT but %qE is not marked"
" %<throw()%> or %<noexcept%>", grooaf, promise_type, nwname);
}
- else
+ else /* No operator new in the promise. */
{
/* [dcl.fct.def.coroutine] / 9 (part 4)
If this lookup fails, the allocation function’s name is looked up in
@@ -4009,7 +4003,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
/* build_operator_new_call () will insert size needed as element 0 of
this, and we might need to append the std::nothrow constant. */
vec_alloc (args, 2);
-
if (grooaf)
{
/* [dcl.fct.def.coroutine] / 10 (part 2)
@@ -4023,6 +4016,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree std_nt = lookup_qualified_name (std_node,
get_identifier ("nothrow"),
0, /*complain=*/true, false);
+ if (!std_nt || std_nt == error_mark_node)
+ error_at (fn_start, "%qE is provided by %qT but %<std::nothrow%> "
+ "cannot be found", grooaf, promise_type);
vec_safe_push (args, std_nt);
}
@@ -4037,7 +4033,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tf_warning_or_error);
resizeable = build_call_expr_internal_loc
(fn_start, IFN_CO_FRAME, size_type_node, 2, frame_size, coro_fp);
- CALL_EXPR_ARG (new_fn, 0) = resizeable;
+ /* If the operator call fails for some reason, then don't try to
+ amend it. */
+ if (new_fn != error_mark_node)
+ CALL_EXPR_ARG (new_fn, 0) = resizeable;
release_tree_vector (args);
}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr95505.C b/gcc/testsuite/g++.dg/coroutines/pr95505.C
new file mode 100644
index 0000000..a76b827
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr95505.C
@@ -0,0 +1,26 @@
+#if __has_include (<coroutine>)
+#include <coroutine>
+using namespace std;
+#elif defined (__clang__) && __has_include (<experimental/coroutine>)
+#include <experimental/coroutine>
+namespace std { using namespace experimental; }
+#endif
+
+struct dummy
+{
+ struct promise_type
+ {
+ dummy get_return_object() const noexcept { return {}; }
+ static dummy get_return_object_on_allocation_failure() noexcept { return {}; }
+ std::suspend_always initial_suspend() const noexcept { return {}; }
+ std::suspend_never final_suspend() const noexcept { return {}; }
+ void return_void() const noexcept {}
+ void unhandled_exception() const noexcept {}
+ };
+};
+
+dummy foo() // { dg-error {dummy::promise_type::get_return_object_on_allocation_failure.*but 'std::nothrow' cannot be found} }
+{
+ co_return;
+}
+