Hi, PR98118 shows that TYPE_NEEDS_CONSTRUCTING is a necessary, but not sufficient, condition for determining when we need to build a constructor. Use type_build_ctor_call() instead.
tested on x86_64-darwin, x86_64-linux-gnu, [ ice on valid ] OK for master / 10.x? thanks Iain gcc/cp/ChangeLog: PR c++/98118 * coroutines.cc (build_co_await): Use type_build_ctor_call() to determine cases when a CTOR needs to be built. (flatten_await_stmt): Likewise. (morph_fn_to_coro): Likewise. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr98118.C: New test. --- gcc/cp/coroutines.cc | 14 +++++------ gcc/testsuite/g++.dg/coroutines/pr98118.C | 29 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/pr98118.C diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index f79ac60dc77..2f4208fe57c 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -949,7 +949,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) e_proxy = o; o = NULL_TREE; /* The var is already present. */ } - else if (CLASS_TYPE_P (o_type) || TYPE_NEEDS_CONSTRUCTING (o_type)) + else if (type_build_ctor_call (o_type)) { e_proxy = get_awaitable_var (suspend_kind, o_type); releasing_vec arg (make_tree_vector_single (rvalue (o))); @@ -2965,7 +2965,7 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted, gcc_checking_assert (!already_present); tree inner = TREE_OPERAND (init, 1); gcc_checking_assert (TREE_CODE (inner) != COND_EXPR); - if (TYPE_NEEDS_CONSTRUCTING (var_type)) + if (type_build_ctor_call (var_type)) { releasing_vec p_in (make_tree_vector_single (init)); init = build_special_member_call (var, complete_ctor_identifier, @@ -2977,9 +2977,9 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted, var_nest_node *ins = new var_nest_node (var, init, n->prev, n); /* We have to replace the target expr... */ - proxy_replace pr = {TREE_OPERAND (t, 0), var}; *v.entry = var; /* ... and any uses of its var. */ + proxy_replace pr = {TREE_OPERAND (t, 0), var}; cp_walk_tree (&n->init, replace_proxy, &pr, NULL); /* Compiler-generated temporaries can also have uses in following arms of compound expressions, which will be listed in 'replace_in' @@ -4680,7 +4680,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) parm.frame_type, INIT_EXPR, DECL_SOURCE_LOCATION (arg), arg, DECL_ARG_TYPE (arg)); - else if (TYPE_NEEDS_CONSTRUCTING (parm.frame_type)) + else if (type_build_ctor_call (parm.frame_type)) { vec<tree, va_gc> *p_in; if (CLASS_TYPE_P (parm.frame_type) @@ -4738,7 +4738,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) false, tf_warning_or_error); tree promise_dtor = NULL_TREE; - if (TYPE_NEEDS_CONSTRUCTING (promise_type)) + if (type_build_ctor_call (promise_type)) { /* Do a placement new constructor for the promise type (we never call the new operator, just the constructor on the object in place in the @@ -4819,7 +4819,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) The expression promise.get_return_object() is used to initialize the glvalue result or... (see below) Construct the return result directly. */ - if (TYPE_NEEDS_CONSTRUCTING (gro_type)) + if (type_build_ctor_call (gro_type)) { vec<tree, va_gc> *arg = make_tree_vector_single (get_ro); r = build_special_member_call (DECL_RESULT (orig), @@ -4852,7 +4852,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) DECL_IGNORED_P (gro) = true; add_decl_expr (gro); gro_bind_vars = gro; - if (TYPE_NEEDS_CONSTRUCTING (gro_type)) + if (type_build_ctor_call (gro_type)) { vec<tree, va_gc> *arg = make_tree_vector_single (get_ro); r = build_special_member_call (gro, complete_ctor_identifier, diff --git a/gcc/testsuite/g++.dg/coroutines/pr98118.C b/gcc/testsuite/g++.dg/coroutines/pr98118.C new file mode 100644 index 00000000000..d09ffff2142 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr98118.C @@ -0,0 +1,29 @@ +namespace std { +inline namespace __n4861 { +template <typename _Result, typename> struct coroutine_traits : _Result {}; +template <typename = void> struct coroutine_handle; +template <> struct coroutine_handle<> {}; +template <typename> struct coroutine_handle : coroutine_handle<> {}; +struct suspend_never { + bool await_ready() noexcept; + void await_suspend(coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; +} // namespace __n4861 +} // namespace std + +struct fire_and_forget { + struct promise_type { + fire_and_forget get_return_object(); + std::suspend_never initial_suspend(); + std::suspend_never final_suspend() noexcept; + void return_void(); + void unhandled_exception(); + }; +}; + +struct bug { + ~bug(); +}; + +fire_and_forget f(bug) { co_return; } -- 2.24.1