diff options
author | Iain Sandoe <iain@sandoe.co.uk> | 2020-06-04 17:14:37 +0100 |
---|---|---|
committer | Iain Sandoe <iain@sandoe.co.uk> | 2020-06-04 19:26:18 +0100 |
commit | 4f2d05ef0142d269964e165c14c6f7fe4bdfd5a3 (patch) | |
tree | 5daf10eeceaa56efd48462880df814b2fdc81e2f /gcc/cp | |
parent | e7ef9a40cd0c688cd331bc26224d1fbe360c1fe6 (diff) | |
download | gcc-4f2d05ef0142d269964e165c14c6f7fe4bdfd5a3.zip gcc-4f2d05ef0142d269964e165c14c6f7fe4bdfd5a3.tar.gz gcc-4f2d05ef0142d269964e165c14c6f7fe4bdfd5a3.tar.bz2 |
coroutines: Fix missed ramp function return copy elision [PR95346].
Confusingly, "get_return_object ()" can do two things:
- Firstly it can provide the return object for the ramp function (as
the name suggests).
- Secondly if the type of the ramp function is different from that
of the get_return_object call, this is used as a single parameter
to a CTOR for the ramp's return type.
In the first case we can rely on finish_return_stmt () to do the
necessary processing for copy elision.
In the second case, we should have passed a prvalue to the CTOR as
per the standard comment, but I had omitted the rvalue () call. Fixed
thus.
gcc/cp/ChangeLog:
PR c++/95346
* coroutines.cc (morph_fn_to_coro): Ensure that the get-
return-object is constructed correctly; When it is not the
final return value, pass it to the CTOR of the return type
as an rvalue, per the standard comment.
gcc/testsuite/ChangeLog:
PR c++/95346
* g++.dg/coroutines/pr95346.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/coroutines.cc | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 58102f5..e86b3d4 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4284,7 +4284,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) } tree gro_context_body = push_stmt_list (); - bool gro_is_void_p = VOID_TYPE_P (TREE_TYPE (get_ro)); + tree gro_type = TREE_TYPE (get_ro); + bool gro_is_void_p = VOID_TYPE_P (gro_type); tree gro = NULL_TREE; tree gro_bind_vars = NULL_TREE; @@ -4294,17 +4295,23 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) finish_expr_stmt (get_ro); else { - gro = build_lang_decl (VAR_DECL, get_identifier ("coro.gro"), - TREE_TYPE (get_ro)); + gro = build_lang_decl (VAR_DECL, get_identifier ("coro.gro"), gro_type); DECL_CONTEXT (gro) = current_scope (); DECL_ARTIFICIAL (gro) = true; DECL_IGNORED_P (gro) = true; add_decl_expr (gro); gro_bind_vars = gro; - - r = build2_loc (fn_start, INIT_EXPR, TREE_TYPE (gro), gro, get_ro); - r = coro_build_cvt_void_expr_stmt (r, fn_start); - add_stmt (r); + if (TYPE_NEEDS_CONSTRUCTING (gro_type)) + { + vec<tree, va_gc> *arg = make_tree_vector_single (get_ro); + r = build_special_member_call (gro, complete_ctor_identifier, + &arg, gro_type, LOOKUP_NORMAL, + tf_warning_or_error); + release_tree_vector (arg); + } + else + r = build2_loc (fn_start, INIT_EXPR, gro_type, gro, get_ro); + finish_expr_stmt (r); } /* Initialize the resume_idx_name to 0, meaning "not started". */ @@ -4338,28 +4345,43 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Switch to using 'input_location' as the loc, since we're now more logically doing things related to the end of the function. */ - /* The ramp is done, we just need the return value. */ - if (!same_type_p (TREE_TYPE (get_ro), fn_return_type)) + /* The ramp is done, we just need the return value. + [dcl.fct.def.coroutine] / 7 + The expression promise.get_return_object() is used to initialize the + glvalue result or prvalue result object of a call to a coroutine. + + If the 'get return object' is non-void, then we built it before the + promise was constructed. We now supply a reference to that var, + either as the return value (if it's the same type) or to the CTOR + for an object of the return type. */ + if (gro_is_void_p) + r = NULL_TREE; + else + r = rvalue (gro); + + if (!same_type_p (gro_type, fn_return_type)) { - /* construct the return value with a single GRO param, if it's not - void. */ - vec<tree, va_gc> *args = NULL; - vec<tree, va_gc> **arglist = NULL; - if (!gro_is_void_p) + /* The return object is , even if the gro is void. */ + if (CLASS_TYPE_P (fn_return_type)) { - args = make_tree_vector_single (gro); - arglist = &args; + vec<tree, va_gc> *args = NULL; + vec<tree, va_gc> **arglist = NULL; + if (!gro_is_void_p) + { + args = make_tree_vector_single (r); + arglist = &args; + } + r = build_special_member_call (NULL_TREE, + complete_ctor_identifier, arglist, + fn_return_type, LOOKUP_NORMAL, + tf_warning_or_error); + r = build_cplus_new (fn_return_type, r, tf_warning_or_error); + if (args) + release_tree_vector (args); } - r = build_special_member_call (NULL_TREE, - complete_ctor_identifier, arglist, - fn_return_type, LOOKUP_NORMAL, - tf_warning_or_error); - r = build_cplus_new (fn_return_type, r, tf_warning_or_error); + else /* ??? suppose we have non-class return and void gro? */ + r = build1_loc (input_location, CONVERT_EXPR, fn_return_type, r); } - else if (!gro_is_void_p) - r = rvalue (gro); /* The GRO is the return value. */ - else - r = NULL_TREE; finish_return_stmt (r); |