Commit a59a15bc by Iain Sandoe

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.

(cherry picked from commit 445d8da5fbd10e32f8ea470bd9ac02faba8fd718)
parent e80ee62b
......@@ -3924,31 +3924,26 @@ 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:
n4849 [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))
{
/* n4849 [dcl.fct.def.coroutine] / 9 (part 2)
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
assembling an argument list. The first argument is the amount of space
......@@ -3977,30 +3972,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)
{
/* n4849 [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);
......@@ -4010,7 +4004,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. */
{
/* n4849 [dcl.fct.def.coroutine] / 9 (part 4)
If this lookup fails, the allocation function’s name is looked up in
......@@ -4020,7 +4014,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)
{
/* n4849 [dcl.fct.def.coroutine] / 10 (part 2)
......@@ -4034,6 +4027,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);
}
......@@ -4048,7 +4044,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);
}
......
#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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment