1 /* coroutine-specific state, expansions and tests.
2
3 Copyright (C) 2018-2021 Free Software Foundation, Inc.
4
5 Contributed by Iain Sandoe <iain@sandoe.co.uk> under contract to Facebook.
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
12 version.
13
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "target.h"
27 #include "cp-tree.h"
28 #include "stringpool.h"
29 #include "stmt.h"
30 #include "stor-layout.h"
31 #include "tree-iterator.h"
32 #include "tree.h"
33 #include "gcc-rich-location.h"
34 #include "hash-map.h"
35
36 static bool coro_promise_type_found_p (tree, location_t);
37
38 /* GCC C++ coroutines implementation.
39
40 The user authors a function that becomes a coroutine (lazily) by
41 making use of any of the co_await, co_yield or co_return keywords.
42
43 Unlike a regular function, where the activation record is placed on the
44 stack, and is destroyed on function exit, a coroutine has some state that
45 persists between calls - the coroutine frame (analogous to a stack frame).
46
47 We transform the user's function into three pieces:
48 1. A so-called ramp function, that establishes the coroutine frame and
49 begins execution of the coroutine.
50 2. An actor function that contains the state machine corresponding to the
51 user's suspend/resume structure.
52 3. A stub function that calls the actor function in 'destroy' mode.
53
54 The actor function is executed:
55 * from "resume point 0" by the ramp.
56 * from resume point N ( > 0 ) for handle.resume() calls.
57 * from the destroy stub for destroy point N for handle.destroy() calls.
58
59 The functions in this file carry out the necessary analysis of, and
60 transforms to, the AST to perform this.
61
62 The C++ coroutine design makes use of some helper functions that are
63 authored in a so-called "promise" class provided by the user.
64
65 At parse time (or post substitution) the type of the coroutine promise
66 will be determined. At that point, we can look up the required promise
67 class methods and issue diagnostics if they are missing or incorrect. To
68 avoid repeating these actions at code-gen time, we make use of temporary
69 'proxy' variables for the coroutine handle and the promise - which will
70 eventually be instantiated in the coroutine frame.
71
72 Each of the keywords will expand to a code sequence (although co_yield is
73 just syntactic sugar for a co_await).
74
75 We defer the analysis and transformation until template expansion is
76 complete so that we have complete types at that time. */
77
78
79 /* The state that we collect during parsing (and template expansion) for
80 a coroutine. */
81
82 struct GTY((for_user)) coroutine_info
83 {
84 tree function_decl; /* The original function decl. */
85 tree actor_decl; /* The synthesized actor function. */
86 tree destroy_decl; /* The synthesized destroy function. */
87 tree promise_type; /* The cached promise type for this function. */
88 tree handle_type; /* The cached coroutine handle for this function. */
89 tree self_h_proxy; /* A handle instance that is used as the proxy for the
90 one that will eventually be allocated in the coroutine
91 frame. */
92 tree promise_proxy; /* Likewise, a proxy promise instance. */
93 tree return_void; /* The expression for p.return_void() if it exists. */
94 location_t first_coro_keyword; /* The location of the keyword that made this
95 function into a coroutine. */
96 /* Flags to avoid repeated errors for per-function issues. */
97 bool coro_ret_type_error_emitted;
98 bool coro_promise_error_emitted;
99 bool coro_co_return_error_emitted;
100 };
101
102 struct coroutine_info_hasher : ggc_ptr_hash<coroutine_info>
103 {
104 typedef tree compare_type; /* We only compare the function decl. */
105 static inline hashval_t hash (coroutine_info *);
106 static inline hashval_t hash (const compare_type &);
107 static inline bool equal (coroutine_info *, coroutine_info *);
108 static inline bool equal (coroutine_info *, const compare_type &);
109 };
110
111 /* This table holds all the collected coroutine state for coroutines in
112 the current translation unit. */
113
114 static GTY (()) hash_table<coroutine_info_hasher> *coroutine_info_table;
115
116 /* We will initialize state lazily. */
117 static bool coro_initialized = false;
118
119 /* Return a hash value for the entry pointed to by INFO.
120 The compare type is a tree, but the only trees we are going use are
121 function decls. We use the DECL_UID as the hash value since that is
122 stable across PCH. */
123
124 hashval_t
hash(coroutine_info * info)125 coroutine_info_hasher::hash (coroutine_info *info)
126 {
127 return DECL_UID (info->function_decl);
128 }
129
130 /* Return a hash value for the compare value COMP. */
131
132 hashval_t
hash(const compare_type & comp)133 coroutine_info_hasher::hash (const compare_type& comp)
134 {
135 return DECL_UID (comp);
136 }
137
138 /* Return true if the entries pointed to by LHS and RHS are for the
139 same coroutine. */
140
141 bool
equal(coroutine_info * lhs,coroutine_info * rhs)142 coroutine_info_hasher::equal (coroutine_info *lhs, coroutine_info *rhs)
143 {
144 return lhs->function_decl == rhs->function_decl;
145 }
146
147 bool
equal(coroutine_info * lhs,const compare_type & rhs)148 coroutine_info_hasher::equal (coroutine_info *lhs, const compare_type& rhs)
149 {
150 return lhs->function_decl == rhs;
151 }
152
153 /* Get the existing coroutine_info for FN_DECL, or insert a new one if the
154 entry does not yet exist. */
155
156 coroutine_info *
get_or_insert_coroutine_info(tree fn_decl)157 get_or_insert_coroutine_info (tree fn_decl)
158 {
159 gcc_checking_assert (coroutine_info_table != NULL);
160
161 coroutine_info **slot = coroutine_info_table->find_slot_with_hash
162 (fn_decl, coroutine_info_hasher::hash (fn_decl), INSERT);
163
164 if (*slot == NULL)
165 {
166 *slot = new (ggc_cleared_alloc<coroutine_info> ()) coroutine_info ();
167 (*slot)->function_decl = fn_decl;
168 }
169
170 return *slot;
171 }
172
173 /* Get the existing coroutine_info for FN_DECL, fail if it doesn't exist. */
174
175 coroutine_info *
get_coroutine_info(tree fn_decl)176 get_coroutine_info (tree fn_decl)
177 {
178 if (coroutine_info_table == NULL)
179 return NULL;
180
181 coroutine_info **slot = coroutine_info_table->find_slot_with_hash
182 (fn_decl, coroutine_info_hasher::hash (fn_decl), NO_INSERT);
183 if (slot)
184 return *slot;
185 return NULL;
186 }
187
188 /* We will lazily create all the identifiers that are used by coroutines
189 on the first attempt to lookup the traits. */
190
191 /* Identifiers that are used by all coroutines. */
192
193 static GTY(()) tree coro_traits_identifier;
194 static GTY(()) tree coro_handle_identifier;
195 static GTY(()) tree coro_promise_type_identifier;
196
197 /* Required promise method name identifiers. */
198
199 static GTY(()) tree coro_await_transform_identifier;
200 static GTY(()) tree coro_initial_suspend_identifier;
201 static GTY(()) tree coro_final_suspend_identifier;
202 static GTY(()) tree coro_return_void_identifier;
203 static GTY(()) tree coro_return_value_identifier;
204 static GTY(()) tree coro_yield_value_identifier;
205 static GTY(()) tree coro_resume_identifier;
206 static GTY(()) tree coro_address_identifier;
207 static GTY(()) tree coro_from_address_identifier;
208 static GTY(()) tree coro_get_return_object_identifier;
209 static GTY(()) tree coro_gro_on_allocation_fail_identifier;
210 static GTY(()) tree coro_unhandled_exception_identifier;
211
212 /* Awaitable methods. */
213
214 static GTY(()) tree coro_await_ready_identifier;
215 static GTY(()) tree coro_await_suspend_identifier;
216 static GTY(()) tree coro_await_resume_identifier;
217
218 /* Create the identifiers used by the coroutines library interfaces. */
219
220 static void
coro_init_identifiers()221 coro_init_identifiers ()
222 {
223 coro_traits_identifier = get_identifier ("coroutine_traits");
224 coro_handle_identifier = get_identifier ("coroutine_handle");
225 coro_promise_type_identifier = get_identifier ("promise_type");
226
227 coro_await_transform_identifier = get_identifier ("await_transform");
228 coro_initial_suspend_identifier = get_identifier ("initial_suspend");
229 coro_final_suspend_identifier = get_identifier ("final_suspend");
230 coro_return_void_identifier = get_identifier ("return_void");
231 coro_return_value_identifier = get_identifier ("return_value");
232 coro_yield_value_identifier = get_identifier ("yield_value");
233 coro_resume_identifier = get_identifier ("resume");
234 coro_address_identifier = get_identifier ("address");
235 coro_from_address_identifier = get_identifier ("from_address");
236 coro_get_return_object_identifier = get_identifier ("get_return_object");
237 coro_gro_on_allocation_fail_identifier =
238 get_identifier ("get_return_object_on_allocation_failure");
239 coro_unhandled_exception_identifier = get_identifier ("unhandled_exception");
240
241 coro_await_ready_identifier = get_identifier ("await_ready");
242 coro_await_suspend_identifier = get_identifier ("await_suspend");
243 coro_await_resume_identifier = get_identifier ("await_resume");
244 }
245
246 /* Trees we only need to set up once. */
247
248 static GTY(()) tree coro_traits_templ;
249 static GTY(()) tree coro_handle_templ;
250 static GTY(()) tree void_coro_handle_type;
251
252 /* ================= Parse, Semantics and Type checking ================= */
253
254 /* This initial set of routines are helper for the parsing and template
255 expansion phases.
256
257 At the completion of this, we will have completed trees for each of the
258 keywords, but making use of proxy variables for the self-handle and the
259 promise class instance. */
260
261 /* [coroutine.traits]
262 Lookup the coroutine_traits template decl. */
263
264 static tree
find_coro_traits_template_decl(location_t kw)265 find_coro_traits_template_decl (location_t kw)
266 {
267 /* If we are missing fundamental information, such as the traits, (or the
268 declaration found is not a type template), then don't emit an error for
269 every keyword in a TU, just do it once. */
270 static bool traits_error_emitted = false;
271
272 tree traits_decl = lookup_qualified_name (std_node, coro_traits_identifier,
273 LOOK_want::NORMAL,
274 /*complain=*/!traits_error_emitted);
275 if (traits_decl == error_mark_node
276 || !DECL_TYPE_TEMPLATE_P (traits_decl))
277 {
278 if (!traits_error_emitted)
279 {
280 gcc_rich_location richloc (kw);
281 error_at (&richloc, "coroutines require a traits template; cannot"
282 " find %<%E::%E%>", std_node, coro_traits_identifier);
283 inform (&richloc, "perhaps %<#include <coroutine>%> is missing");
284 traits_error_emitted = true;
285 }
286 return NULL_TREE;
287 }
288 else
289 return traits_decl;
290 }
291
292 /* Instantiate Coroutine traits for the function signature. */
293
294 static tree
instantiate_coro_traits(tree fndecl,location_t kw)295 instantiate_coro_traits (tree fndecl, location_t kw)
296 {
297 /* [coroutine.traits.primary]
298 So now build up a type list for the template <typename _R, typename...>.
299 The types are the function's arg types and _R is the function return
300 type. */
301
302 tree functyp = TREE_TYPE (fndecl);
303 tree arg = DECL_ARGUMENTS (fndecl);
304 tree arg_node = TYPE_ARG_TYPES (functyp);
305 tree argtypes = make_tree_vec (list_length (arg_node)-1);
306 unsigned p = 0;
307
308 while (arg_node != NULL_TREE && !VOID_TYPE_P (TREE_VALUE (arg_node)))
309 {
310 if (is_this_parameter (arg)
311 || DECL_NAME (arg) == closure_identifier)
312 {
313 /* We pass a reference to *this to the param preview. */
314 tree ct = TREE_TYPE (TREE_TYPE (arg));
315 TREE_VEC_ELT (argtypes, p++) = cp_build_reference_type (ct, false);
316 }
317 else
318 TREE_VEC_ELT (argtypes, p++) = TREE_VALUE (arg_node);
319
320 arg_node = TREE_CHAIN (arg_node);
321 arg = DECL_CHAIN (arg);
322 }
323
324 tree argtypepack = cxx_make_type (TYPE_ARGUMENT_PACK);
325 SET_ARGUMENT_PACK_ARGS (argtypepack, argtypes);
326
327 tree targ = make_tree_vec (2);
328 TREE_VEC_ELT (targ, 0) = TREE_TYPE (functyp);
329 TREE_VEC_ELT (targ, 1) = argtypepack;
330
331 tree traits_class
332 = lookup_template_class (coro_traits_templ, targ,
333 /*in_decl=*/NULL_TREE, /*context=*/NULL_TREE,
334 /*entering scope=*/false, tf_warning_or_error);
335
336 if (traits_class == error_mark_node)
337 {
338 error_at (kw, "cannot instantiate %<coroutine traits%>");
339 return NULL_TREE;
340 }
341
342 return traits_class;
343 }
344
345 /* [coroutine.handle] */
346
347 static tree
find_coro_handle_template_decl(location_t kw)348 find_coro_handle_template_decl (location_t kw)
349 {
350 /* As for the coroutine traits, this error is per TU, so only emit
351 it once. */
352 static bool coro_handle_error_emitted = false;
353 tree handle_decl = lookup_qualified_name (std_node, coro_handle_identifier,
354 LOOK_want::NORMAL,
355 !coro_handle_error_emitted);
356 if (handle_decl == error_mark_node
357 || !DECL_CLASS_TEMPLATE_P (handle_decl))
358 {
359 if (!coro_handle_error_emitted)
360 error_at (kw, "coroutines require a handle class template;"
361 " cannot find %<%E::%E%>", std_node, coro_handle_identifier);
362 coro_handle_error_emitted = true;
363 return NULL_TREE;
364 }
365 else
366 return handle_decl;
367 }
368
369 /* Instantiate the handle template for a given promise type. */
370
371 static tree
instantiate_coro_handle_for_promise_type(location_t kw,tree promise_type)372 instantiate_coro_handle_for_promise_type (location_t kw, tree promise_type)
373 {
374 /* So now build up a type list for the template, one entry, the promise. */
375 tree targ = make_tree_vec (1);
376 TREE_VEC_ELT (targ, 0) = promise_type;
377 tree handle_type
378 = lookup_template_class (coro_handle_identifier, targ,
379 /* in_decl=*/NULL_TREE,
380 /* context=*/std_node,
381 /* entering scope=*/false, tf_warning_or_error);
382
383 if (handle_type == error_mark_node)
384 {
385 error_at (kw, "cannot instantiate a %<coroutine handle%> for"
386 " promise type %qT", promise_type);
387 return NULL_TREE;
388 }
389
390 return handle_type;
391 }
392
393 /* Look for the promise_type in the instantiated traits. */
394
395 static tree
find_promise_type(tree traits_class)396 find_promise_type (tree traits_class)
397 {
398 tree promise_type
399 = lookup_member (traits_class, coro_promise_type_identifier,
400 /* protect=*/1, /*want_type=*/true, tf_warning_or_error);
401
402 if (promise_type)
403 promise_type
404 = complete_type_or_else (TREE_TYPE (promise_type), promise_type);
405
406 /* NULL_TREE on fail. */
407 return promise_type;
408 }
409
410 static bool
coro_promise_type_found_p(tree fndecl,location_t loc)411 coro_promise_type_found_p (tree fndecl, location_t loc)
412 {
413 gcc_assert (fndecl != NULL_TREE);
414
415 if (!coro_initialized)
416 {
417 /* Trees we only need to create once.
418 Set up the identifiers we will use. */
419 coro_init_identifiers ();
420
421 /* Coroutine traits template. */
422 coro_traits_templ = find_coro_traits_template_decl (loc);
423 if (coro_traits_templ == NULL_TREE)
424 return false;
425
426 /* coroutine_handle<> template. */
427 coro_handle_templ = find_coro_handle_template_decl (loc);
428 if (coro_handle_templ == NULL_TREE)
429 return false;
430
431 /* We can also instantiate the void coroutine_handle<> */
432 void_coro_handle_type =
433 instantiate_coro_handle_for_promise_type (loc, NULL_TREE);
434 if (void_coro_handle_type == NULL_TREE)
435 return false;
436
437 /* A table to hold the state, per coroutine decl. */
438 gcc_checking_assert (coroutine_info_table == NULL);
439 coroutine_info_table =
440 hash_table<coroutine_info_hasher>::create_ggc (11);
441
442 if (coroutine_info_table == NULL)
443 return false;
444
445 coro_initialized = true;
446 }
447
448 /* Save the coroutine data on the side to avoid the overhead on every
449 function decl tree. */
450
451 coroutine_info *coro_info = get_or_insert_coroutine_info (fndecl);
452 /* Without this, we cannot really proceed. */
453 gcc_checking_assert (coro_info);
454
455 /* If we don't already have a current promise type, try to look it up. */
456 if (coro_info->promise_type == NULL_TREE)
457 {
458 /* Get the coroutine traits template class instance for the function
459 signature we have - coroutine_traits <R, ...> */
460
461 tree templ_class = instantiate_coro_traits (fndecl, loc);
462
463 /* Find the promise type for that. */
464 coro_info->promise_type = find_promise_type (templ_class);
465
466 /* If we don't find it, punt on the rest. */
467 if (coro_info->promise_type == NULL_TREE)
468 {
469 if (!coro_info->coro_promise_error_emitted)
470 error_at (loc, "unable to find the promise type for"
471 " this coroutine");
472 coro_info->coro_promise_error_emitted = true;
473 return false;
474 }
475
476 /* Test for errors in the promise type that can be determined now. */
477 tree has_ret_void = lookup_member (coro_info->promise_type,
478 coro_return_void_identifier,
479 /*protect=*/1, /*want_type=*/0,
480 tf_none);
481 tree has_ret_val = lookup_member (coro_info->promise_type,
482 coro_return_value_identifier,
483 /*protect=*/1, /*want_type=*/0,
484 tf_none);
485 if (has_ret_void && has_ret_val)
486 {
487 location_t ploc = DECL_SOURCE_LOCATION (fndecl);
488 if (!coro_info->coro_co_return_error_emitted)
489 error_at (ploc, "the coroutine promise type %qT declares both"
490 " %<return_value%> and %<return_void%>",
491 coro_info->promise_type);
492 inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_void)),
493 "%<return_void%> declared here");
494 inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_val)),
495 "%<return_value%> declared here");
496 coro_info->coro_co_return_error_emitted = true;
497 return false;
498 }
499
500 /* Try to find the handle type for the promise. */
501 tree handle_type =
502 instantiate_coro_handle_for_promise_type (loc, coro_info->promise_type);
503 if (handle_type == NULL_TREE)
504 return false;
505
506 /* Complete this, we're going to use it. */
507 coro_info->handle_type = complete_type_or_else (handle_type, fndecl);
508
509 /* Diagnostic would be emitted by complete_type_or_else. */
510 if (!coro_info->handle_type)
511 return false;
512
513 /* Build a proxy for a handle to "self" as the param to
514 await_suspend() calls. */
515 coro_info->self_h_proxy
516 = build_lang_decl (VAR_DECL, get_identifier ("self_h.proxy"),
517 coro_info->handle_type);
518
519 /* Build a proxy for the promise so that we can perform lookups. */
520 coro_info->promise_proxy
521 = build_lang_decl (VAR_DECL, get_identifier ("promise.proxy"),
522 coro_info->promise_type);
523
524 /* Note where we first saw a coroutine keyword. */
525 coro_info->first_coro_keyword = loc;
526 }
527
528 return true;
529 }
530
531 /* Map from actor or destroyer to ramp. */
532 static GTY(()) hash_map<tree, tree> *to_ramp;
533
534 /* Given a tree that is an actor or destroy, find the ramp function. */
535
536 tree
coro_get_ramp_function(tree decl)537 coro_get_ramp_function (tree decl)
538 {
539 if (!to_ramp)
540 return NULL_TREE;
541 tree *p = to_ramp->get (decl);
542 if (p)
543 return *p;
544 return NULL_TREE;
545 }
546
547 /* Given the DECL for a ramp function (the user's original declaration) return
548 the actor function if it has been defined. */
549
550 tree
coro_get_actor_function(tree decl)551 coro_get_actor_function (tree decl)
552 {
553 if (coroutine_info *info = get_coroutine_info (decl))
554 return info->actor_decl;
555
556 return NULL_TREE;
557 }
558
559 /* Given the DECL for a ramp function (the user's original declaration) return
560 the destroy function if it has been defined. */
561
562 tree
coro_get_destroy_function(tree decl)563 coro_get_destroy_function (tree decl)
564 {
565 if (coroutine_info *info = get_coroutine_info (decl))
566 return info->destroy_decl;
567
568 return NULL_TREE;
569 }
570
571 /* These functions assumes that the caller has verified that the state for
572 the decl has been initialized, we try to minimize work here. */
573
574 static tree
get_coroutine_promise_type(tree decl)575 get_coroutine_promise_type (tree decl)
576 {
577 if (coroutine_info *info = get_coroutine_info (decl))
578 return info->promise_type;
579
580 return NULL_TREE;
581 }
582
583 static tree
get_coroutine_handle_type(tree decl)584 get_coroutine_handle_type (tree decl)
585 {
586 if (coroutine_info *info = get_coroutine_info (decl))
587 return info->handle_type;
588
589 return NULL_TREE;
590 }
591
592 static tree
get_coroutine_self_handle_proxy(tree decl)593 get_coroutine_self_handle_proxy (tree decl)
594 {
595 if (coroutine_info *info = get_coroutine_info (decl))
596 return info->self_h_proxy;
597
598 return NULL_TREE;
599 }
600
601 static tree
get_coroutine_promise_proxy(tree decl)602 get_coroutine_promise_proxy (tree decl)
603 {
604 if (coroutine_info *info = get_coroutine_info (decl))
605 return info->promise_proxy;
606
607 return NULL_TREE;
608 }
609
610 static tree
lookup_promise_method(tree fndecl,tree member_id,location_t loc,bool musthave)611 lookup_promise_method (tree fndecl, tree member_id, location_t loc,
612 bool musthave)
613 {
614 tree promise = get_coroutine_promise_type (fndecl);
615 tree pm_memb
616 = lookup_member (promise, member_id,
617 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
618 if (musthave && pm_memb == NULL_TREE)
619 {
620 error_at (loc, "no member named %qE in %qT", member_id, promise);
621 return error_mark_node;
622 }
623 return pm_memb;
624 }
625
626 /* Build an expression of the form p.method (args) where the p is a promise
627 object for the current coroutine.
628 OBJECT is the promise object instance to use, it may be NULL, in which case
629 we will use the promise_proxy instance for this coroutine.
630 ARGS may be NULL, for empty parm lists. */
631
632 static tree
coro_build_promise_expression(tree fn,tree promise_obj,tree member_id,location_t loc,vec<tree,va_gc> ** args,bool musthave)633 coro_build_promise_expression (tree fn, tree promise_obj, tree member_id,
634 location_t loc, vec<tree, va_gc> **args,
635 bool musthave)
636 {
637 tree meth = lookup_promise_method (fn, member_id, loc, musthave);
638 if (meth == error_mark_node)
639 return error_mark_node;
640
641 /* If we don't find it, and it isn't needed, an empty return is OK. */
642 if (!meth)
643 return NULL_TREE;
644
645 tree promise
646 = promise_obj ? promise_obj
647 : get_coroutine_promise_proxy (current_function_decl);
648 tree expr;
649 if (BASELINK_P (meth))
650 expr = build_new_method_call (promise, meth, args, NULL_TREE,
651 LOOKUP_NORMAL, NULL, tf_warning_or_error);
652 else
653 {
654 expr = build_class_member_access_expr (promise, meth, NULL_TREE,
655 true, tf_warning_or_error);
656 vec<tree, va_gc> *real_args;
657 if (!args)
658 real_args = make_tree_vector ();
659 else
660 real_args = *args;
661 expr = build_op_call (expr, &real_args, tf_warning_or_error);
662 }
663 return expr;
664 }
665
666 /* Caching get for the expression p.return_void (). */
667
668 static tree
get_coroutine_return_void_expr(tree decl,location_t loc,bool musthave)669 get_coroutine_return_void_expr (tree decl, location_t loc, bool musthave)
670 {
671 if (coroutine_info *info = get_coroutine_info (decl))
672 {
673 /* If we don't have it try to build it. */
674 if (!info->return_void)
675 info->return_void
676 = coro_build_promise_expression (current_function_decl, NULL,
677 coro_return_void_identifier,
678 loc, NULL, musthave);
679 /* Don't return an error if it's an optional call. */
680 if (!musthave && info->return_void == error_mark_node)
681 return NULL_TREE;
682 return info->return_void;
683 }
684 return musthave ? error_mark_node : NULL_TREE;
685 }
686
687 /* Lookup an Awaitable member, which should be await_ready, await_suspend
688 or await_resume. */
689
690 static tree
lookup_awaitable_member(tree await_type,tree member_id,location_t loc)691 lookup_awaitable_member (tree await_type, tree member_id, location_t loc)
692 {
693 tree aw_memb
694 = lookup_member (await_type, member_id,
695 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
696 if (aw_memb == NULL_TREE)
697 {
698 error_at (loc, "no member named %qE in %qT", member_id, await_type);
699 return error_mark_node;
700 }
701 return aw_memb;
702 }
703
704 /* Here we check the constraints that are common to all keywords (since the
705 presence of a coroutine keyword makes the function into a coroutine). */
706
707 static bool
coro_common_keyword_context_valid_p(tree fndecl,location_t kw_loc,const char * kw_name)708 coro_common_keyword_context_valid_p (tree fndecl, location_t kw_loc,
709 const char *kw_name)
710 {
711 if (fndecl == NULL_TREE)
712 {
713 error_at (kw_loc, "%qs cannot be used outside a function", kw_name);
714 return false;
715 }
716
717 /* This is arranged in order of prohibitions in the std. */
718 if (DECL_MAIN_P (fndecl))
719 {
720 /* [basic.start.main] 3. The function main shall not be a coroutine. */
721 error_at (kw_loc, "%qs cannot be used in the %<main%> function",
722 kw_name);
723 return false;
724 }
725
726 if (DECL_DECLARED_CONSTEXPR_P (fndecl))
727 {
728 cp_function_chain->invalid_constexpr = true;
729 if (!is_instantiation_of_constexpr (fndecl))
730 {
731 /* [dcl.constexpr] 3.3 it shall not be a coroutine. */
732 error_at (kw_loc, "%qs cannot be used in a %<constexpr%> function",
733 kw_name);
734 return false;
735 }
736 }
737
738 if (FNDECL_USED_AUTO (fndecl))
739 {
740 /* [dcl.spec.auto] 15. A function declared with a return type that uses
741 a placeholder type shall not be a coroutine. */
742 error_at (kw_loc,
743 "%qs cannot be used in a function with a deduced return type",
744 kw_name);
745 return false;
746 }
747
748 if (varargs_function_p (fndecl))
749 {
750 /* [dcl.fct.def.coroutine] The parameter-declaration-clause of the
751 coroutine shall not terminate with an ellipsis that is not part
752 of a parameter-declaration. */
753 error_at (kw_loc,
754 "%qs cannot be used in a varargs function", kw_name);
755 return false;
756 }
757
758 if (DECL_CONSTRUCTOR_P (fndecl))
759 {
760 /* [class.ctor] 7. a constructor shall not be a coroutine. */
761 error_at (kw_loc, "%qs cannot be used in a constructor", kw_name);
762 return false;
763 }
764
765 if (DECL_DESTRUCTOR_P (fndecl))
766 {
767 /* [class.dtor] 21. a destructor shall not be a coroutine. */
768 error_at (kw_loc, "%qs cannot be used in a destructor", kw_name);
769 return false;
770 }
771
772 return true;
773 }
774
775 /* Here we check the constraints that are not per keyword. */
776
777 static bool
coro_function_valid_p(tree fndecl)778 coro_function_valid_p (tree fndecl)
779 {
780 location_t f_loc = DECL_SOURCE_LOCATION (fndecl);
781
782 /* For cases where fundamental information cannot be found, e.g. the
783 coroutine traits are missing, we need to punt early. */
784 if (!coro_promise_type_found_p (fndecl, f_loc))
785 return false;
786
787 /* Since we think the function is a coroutine, that implies we parsed
788 a keyword that triggered this. Keywords check promise validity for
789 their context and thus the promise type should be known at this point. */
790 if (get_coroutine_handle_type (fndecl) == NULL_TREE
791 || get_coroutine_promise_type (fndecl) == NULL_TREE)
792 return false;
793
794 if (current_function_returns_value || current_function_returns_null)
795 {
796 /* TODO: record or extract positions of returns (and the first coro
797 keyword) so that we can add notes to the diagnostic about where
798 the bad keyword is and what made the function into a coro. */
799 error_at (f_loc, "a %<return%> statement is not allowed in coroutine;"
800 " did you mean %<co_return%>?");
801 return false;
802 }
803
804 return true;
805 }
806
807 enum suspend_point_kind {
808 CO_AWAIT_SUSPEND_POINT = 0,
809 CO_YIELD_SUSPEND_POINT,
810 INITIAL_SUSPEND_POINT,
811 FINAL_SUSPEND_POINT
812 };
813
814 /* Helper function to build a named variable for the temps we use for each
815 await point. The root of the name is determined by SUSPEND_KIND, and
816 the variable is of type V_TYPE. The awaitable number is reset each time
817 we encounter a final suspend. */
818
819 static tree
get_awaitable_var(suspend_point_kind suspend_kind,tree v_type)820 get_awaitable_var (suspend_point_kind suspend_kind, tree v_type)
821 {
822 static int awn = 0;
823 char *buf;
824 switch (suspend_kind)
825 {
826 default: buf = xasprintf ("Aw%d", awn++); break;
827 case CO_YIELD_SUSPEND_POINT: buf = xasprintf ("Yd%d", awn++); break;
828 case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break;
829 case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); awn = 0; break;
830 }
831 tree ret = get_identifier (buf);
832 free (buf);
833 ret = build_lang_decl (VAR_DECL, ret, v_type);
834 DECL_ARTIFICIAL (ret) = true;
835 return ret;
836 }
837
838 /* Helpers to diagnose missing noexcept on final await expressions. */
839
840 static bool
coro_diagnose_throwing_fn(tree fndecl)841 coro_diagnose_throwing_fn (tree fndecl)
842 {
843 if (!TYPE_NOTHROW_P (TREE_TYPE (fndecl)))
844 {
845 location_t f_loc = cp_expr_loc_or_loc (fndecl,
846 DECL_SOURCE_LOCATION (fndecl));
847 error_at (f_loc, "the expression %qE is required to be non-throwing",
848 fndecl);
849 inform (f_loc, "must be declared with %<noexcept(true)%>");
850 return true;
851 }
852 return false;
853 }
854
855 static bool
coro_diagnose_throwing_final_aw_expr(tree expr)856 coro_diagnose_throwing_final_aw_expr (tree expr)
857 {
858 tree t = TARGET_EXPR_INITIAL (expr);
859 tree fn = NULL_TREE;
860 if (TREE_CODE (t) == CALL_EXPR)
861 fn = CALL_EXPR_FN(t);
862 else if (TREE_CODE (t) == AGGR_INIT_EXPR)
863 fn = AGGR_INIT_EXPR_FN (t);
864 else if (TREE_CODE (t) == CONSTRUCTOR)
865 return false;
866 else
867 {
868 gcc_checking_assert (0 && "unhandled expression type");
869 return false;
870 }
871 fn = TREE_OPERAND (fn, 0);
872 return coro_diagnose_throwing_fn (fn);
873 }
874
875 /* This performs [expr.await] bullet 3.3 and validates the interface obtained.
876 It is also used to build the initial and final suspend points.
877
878 'a', 'o' and 'e' are used as per the description in the section noted.
879
880 A, the original yield/await expr, is found at source location LOC.
881
882 We will be constructing a CO_AWAIT_EXPR for a suspend point of one of
883 the four suspend_point_kind kinds. This is indicated by SUSPEND_KIND. */
884
885 static tree
build_co_await(location_t loc,tree a,suspend_point_kind suspend_kind)886 build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind)
887 {
888 /* Try and overload of operator co_await, .... */
889 tree o;
890 if (MAYBE_CLASS_TYPE_P (TREE_TYPE (a)))
891 {
892 o = build_new_op (loc, CO_AWAIT_EXPR, LOOKUP_NORMAL, a, NULL_TREE,
893 NULL_TREE, NULL, tf_warning_or_error);
894 /* If no viable functions are found, o is a. */
895 if (!o || o == error_mark_node)
896 o = a;
897 else if (flag_exceptions && suspend_kind == FINAL_SUSPEND_POINT)
898 {
899 /* We found an overload for co_await(), diagnose throwing cases. */
900 if (TREE_CODE (o) == TARGET_EXPR
901 && coro_diagnose_throwing_final_aw_expr (o))
902 return error_mark_node;
903
904 /* We now know that the final suspend object is distinct from the
905 final awaiter, so check for a non-throwing DTOR where needed. */
906 tree a_type = TREE_TYPE (a);
907 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (a_type))
908 if (tree dummy
909 = build_special_member_call (a, complete_dtor_identifier,
910 NULL, a_type, LOOKUP_NORMAL,
911 tf_none))
912 {
913 if (CONVERT_EXPR_P (dummy))
914 dummy = TREE_OPERAND (dummy, 0);
915 dummy = TREE_OPERAND (CALL_EXPR_FN (dummy), 0);
916 if (coro_diagnose_throwing_fn (dummy))
917 return error_mark_node;
918 }
919 }
920 }
921 else
922 o = a; /* This is most likely about to fail anyway. */
923
924 tree o_type = TREE_TYPE (o);
925 if (o_type && !VOID_TYPE_P (o_type))
926 o_type = complete_type_or_else (o_type, o);
927
928 if (!o_type)
929 return error_mark_node;
930
931 if (TREE_CODE (o_type) != RECORD_TYPE)
932 {
933 error_at (loc, "awaitable type %qT is not a structure",
934 o_type);
935 return error_mark_node;
936 }
937
938 /* Check for required awaitable members and their types. */
939 tree awrd_meth
940 = lookup_awaitable_member (o_type, coro_await_ready_identifier, loc);
941 if (!awrd_meth || awrd_meth == error_mark_node)
942 return error_mark_node;
943 tree awsp_meth
944 = lookup_awaitable_member (o_type, coro_await_suspend_identifier, loc);
945 if (!awsp_meth || awsp_meth == error_mark_node)
946 return error_mark_node;
947
948 /* The type of the co_await is the return type of the awaitable's
949 await_resume, so we need to look that up. */
950 tree awrs_meth
951 = lookup_awaitable_member (o_type, coro_await_resume_identifier, loc);
952 if (!awrs_meth || awrs_meth == error_mark_node)
953 return error_mark_node;
954
955 /* To complete the lookups, we need an instance of 'e' which is built from
956 'o' according to [expr.await] 3.4.
957
958 If we need to materialize this as a temporary, then that will have to be
959 'promoted' to a coroutine frame var. However, if the awaitable is a
960 user variable, parameter or comes from a scope outside this function,
961 then we must use it directly - or we will see unnecessary copies.
962
963 If o is a variable, find the underlying var. */
964 tree e_proxy = STRIP_NOPS (o);
965 if (INDIRECT_REF_P (e_proxy))
966 e_proxy = TREE_OPERAND (e_proxy, 0);
967 while (TREE_CODE (e_proxy) == COMPONENT_REF)
968 {
969 e_proxy = TREE_OPERAND (e_proxy, 0);
970 if (INDIRECT_REF_P (e_proxy))
971 e_proxy = TREE_OPERAND (e_proxy, 0);
972 if (TREE_CODE (e_proxy) == CALL_EXPR)
973 {
974 /* We could have operator-> here too. */
975 tree op = TREE_OPERAND (CALL_EXPR_FN (e_proxy), 0);
976 if (DECL_OVERLOADED_OPERATOR_P (op)
977 && DECL_OVERLOADED_OPERATOR_IS (op, COMPONENT_REF))
978 {
979 e_proxy = CALL_EXPR_ARG (e_proxy, 0);
980 STRIP_NOPS (e_proxy);
981 gcc_checking_assert (TREE_CODE (e_proxy) == ADDR_EXPR);
982 e_proxy = TREE_OPERAND (e_proxy, 0);
983 }
984 }
985 STRIP_NOPS (e_proxy);
986 }
987
988 /* Only build a temporary if we need it. */
989 if (TREE_CODE (e_proxy) == PARM_DECL
990 || (VAR_P (e_proxy) && !is_local_temp (e_proxy)))
991 {
992 e_proxy = o;
993 o = NULL_TREE; /* The var is already present. */
994 }
995 else if (type_build_ctor_call (o_type))
996 {
997 e_proxy = get_awaitable_var (suspend_kind, o_type);
998 releasing_vec arg (make_tree_vector_single (rvalue (o)));
999 o = build_special_member_call (e_proxy, complete_ctor_identifier,
1000 &arg, o_type, LOOKUP_NORMAL,
1001 tf_warning_or_error);
1002 }
1003 else
1004 {
1005 e_proxy = get_awaitable_var (suspend_kind, o_type);
1006 o = build2 (INIT_EXPR, o_type, e_proxy, rvalue (o));
1007 }
1008
1009 /* I suppose we could check that this is contextually convertible to bool. */
1010 tree awrd_func = NULL_TREE;
1011 tree awrd_call
1012 = build_new_method_call (e_proxy, awrd_meth, NULL, NULL_TREE, LOOKUP_NORMAL,
1013 &awrd_func, tf_warning_or_error);
1014
1015 if (!awrd_func || !awrd_call || awrd_call == error_mark_node)
1016 return error_mark_node;
1017
1018 /* The suspend method may return one of three types:
1019 1. void (no special action needed).
1020 2. bool (if true, we don't need to suspend).
1021 3. a coroutine handle, we execute the handle.resume() call. */
1022 tree awsp_func = NULL_TREE;
1023 tree h_proxy = get_coroutine_self_handle_proxy (current_function_decl);
1024 vec<tree, va_gc> *args = make_tree_vector_single (h_proxy);
1025 tree awsp_call
1026 = build_new_method_call (e_proxy, awsp_meth, &args, NULL_TREE,
1027 LOOKUP_NORMAL, &awsp_func, tf_warning_or_error);
1028
1029 release_tree_vector (args);
1030 if (!awsp_func || !awsp_call || awsp_call == error_mark_node)
1031 return error_mark_node;
1032
1033 bool ok = false;
1034 tree susp_return_type = TREE_TYPE (TREE_TYPE (awsp_func));
1035 if (same_type_p (susp_return_type, void_type_node))
1036 ok = true;
1037 else if (same_type_p (susp_return_type, boolean_type_node))
1038 ok = true;
1039 else if (TREE_CODE (susp_return_type) == RECORD_TYPE
1040 && CLASS_TYPE_P (susp_return_type))
1041 {
1042 tree tt = CLASSTYPE_TI_TEMPLATE (susp_return_type);
1043 if (tt == coro_handle_templ)
1044 ok = true;
1045 }
1046
1047 if (!ok)
1048 {
1049 error_at (loc, "%<await_suspend%> must return %<void%>, %<bool%> or"
1050 " a coroutine handle");
1051 return error_mark_node;
1052 }
1053
1054 /* Finally, the type of e.await_resume() is the co_await's type. */
1055 tree awrs_func = NULL_TREE;
1056 tree awrs_call
1057 = build_new_method_call (e_proxy, awrs_meth, NULL, NULL_TREE, LOOKUP_NORMAL,
1058 &awrs_func, tf_warning_or_error);
1059
1060 if (!awrs_func || !awrs_call || awrs_call == error_mark_node)
1061 return error_mark_node;
1062
1063 if (flag_exceptions && suspend_kind == FINAL_SUSPEND_POINT)
1064 {
1065 if (coro_diagnose_throwing_fn (awrd_func))
1066 return error_mark_node;
1067 if (coro_diagnose_throwing_fn (awsp_func))
1068 return error_mark_node;
1069 if (coro_diagnose_throwing_fn (awrs_func))
1070 return error_mark_node;
1071 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (o_type))
1072 if (tree dummy
1073 = build_special_member_call (e_proxy, complete_dtor_identifier,
1074 NULL, o_type, LOOKUP_NORMAL,
1075 tf_none))
1076 {
1077 if (CONVERT_EXPR_P (dummy))
1078 dummy = TREE_OPERAND (dummy, 0);
1079 dummy = TREE_OPERAND (CALL_EXPR_FN (dummy), 0);
1080 if (coro_diagnose_throwing_fn (dummy))
1081 return error_mark_node;
1082 }
1083 }
1084
1085 /* We now have three call expressions, in terms of the promise, handle and
1086 'e' proxies. Save them in the await expression for later expansion. */
1087
1088 tree awaiter_calls = make_tree_vec (3);
1089 TREE_VEC_ELT (awaiter_calls, 0) = awrd_call; /* await_ready(). */
1090 TREE_VEC_ELT (awaiter_calls, 1) = awsp_call; /* await_suspend(). */
1091 tree te = NULL_TREE;
1092 if (TREE_CODE (awrs_call) == TARGET_EXPR)
1093 {
1094 te = awrs_call;
1095 awrs_call = TREE_OPERAND (awrs_call, 1);
1096 }
1097 TREE_VEC_ELT (awaiter_calls, 2) = awrs_call; /* await_resume(). */
1098
1099 tree await_expr = build5_loc (loc, CO_AWAIT_EXPR,
1100 TREE_TYPE (TREE_TYPE (awrs_func)),
1101 a, e_proxy, o, awaiter_calls,
1102 build_int_cst (integer_type_node,
1103 (int) suspend_kind));
1104 if (te)
1105 {
1106 TREE_OPERAND (te, 1) = await_expr;
1107 await_expr = te;
1108 }
1109 tree t = convert_from_reference (await_expr);
1110 return t;
1111 }
1112
1113 tree
finish_co_await_expr(location_t kw,tree expr)1114 finish_co_await_expr (location_t kw, tree expr)
1115 {
1116 if (!expr || error_operand_p (expr))
1117 return error_mark_node;
1118
1119 if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
1120 "co_await"))
1121 return error_mark_node;
1122
1123 /* The current function has now become a coroutine, if it wasn't already. */
1124 DECL_COROUTINE_P (current_function_decl) = 1;
1125
1126 /* This function will appear to have no return statement, even if it
1127 is declared to return non-void (most likely). This is correct - we
1128 synthesize the return for the ramp in the compiler. So suppress any
1129 extraneous warnings during substitution. */
1130 TREE_NO_WARNING (current_function_decl) = true;
1131
1132 /* If we don't know the promise type, we can't proceed, build the
1133 co_await with the expression unchanged. */
1134 tree functype = TREE_TYPE (current_function_decl);
1135 if (dependent_type_p (functype) || type_dependent_expression_p (expr))
1136 return build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr,
1137 NULL_TREE, NULL_TREE, NULL_TREE, integer_zero_node);
1138
1139 /* We must be able to look up the "await_transform" method in the scope of
1140 the promise type, and obtain its return type. */
1141 if (!coro_promise_type_found_p (current_function_decl, kw))
1142 return error_mark_node;
1143
1144 /* [expr.await] 3.2
1145 The incoming cast expression might be transformed by a promise
1146 'await_transform()'. */
1147 tree at_meth
1148 = lookup_promise_method (current_function_decl,
1149 coro_await_transform_identifier, kw,
1150 /*musthave=*/false);
1151 if (at_meth == error_mark_node)
1152 return error_mark_node;
1153
1154 tree a = expr;
1155 if (at_meth)
1156 {
1157 /* try to build a = p.await_transform (e). */
1158 vec<tree, va_gc> *args = make_tree_vector_single (expr);
1159 a = build_new_method_call (get_coroutine_promise_proxy (
1160 current_function_decl),
1161 at_meth, &args, NULL_TREE, LOOKUP_NORMAL,
1162 NULL, tf_warning_or_error);
1163
1164 /* As I read the section.
1165 We saw an await_transform method, so it's mandatory that we replace
1166 expr with p.await_transform (expr), therefore if the method call fails
1167 (presumably, we don't have suitable arguments) then this part of the
1168 process fails. */
1169 if (a == error_mark_node)
1170 return error_mark_node;
1171 }
1172
1173 /* Now we want to build co_await a. */
1174 tree op = build_co_await (kw, a, CO_AWAIT_SUSPEND_POINT);
1175 if (op != error_mark_node)
1176 {
1177 TREE_SIDE_EFFECTS (op) = 1;
1178 SET_EXPR_LOCATION (op, kw);
1179 }
1180
1181 return op;
1182 }
1183
1184 /* Take the EXPR given and attempt to build:
1185 co_await p.yield_value (expr);
1186 per [expr.yield] para 1. */
1187
1188 tree
finish_co_yield_expr(location_t kw,tree expr)1189 finish_co_yield_expr (location_t kw, tree expr)
1190 {
1191 if (!expr || error_operand_p (expr))
1192 return error_mark_node;
1193
1194 /* Check the general requirements and simple syntax errors. */
1195 if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
1196 "co_yield"))
1197 return error_mark_node;
1198
1199 /* The current function has now become a coroutine, if it wasn't already. */
1200 DECL_COROUTINE_P (current_function_decl) = 1;
1201
1202 /* This function will appear to have no return statement, even if it
1203 is declared to return non-void (most likely). This is correct - we
1204 synthesize the return for the ramp in the compiler. So suppress any
1205 extraneous warnings during substitution. */
1206 TREE_NO_WARNING (current_function_decl) = true;
1207
1208 /* If we don't know the promise type, we can't proceed, build the
1209 co_await with the expression unchanged. */
1210 tree functype = TREE_TYPE (current_function_decl);
1211 if (dependent_type_p (functype) || type_dependent_expression_p (expr))
1212 return build2_loc (kw, CO_YIELD_EXPR, unknown_type_node, expr, NULL_TREE);
1213
1214 if (!coro_promise_type_found_p (current_function_decl, kw))
1215 /* We must be able to look up the "yield_value" method in the scope of
1216 the promise type, and obtain its return type. */
1217 return error_mark_node;
1218
1219 /* [expr.yield] / 1
1220 Let e be the operand of the yield-expression and p be an lvalue naming
1221 the promise object of the enclosing coroutine, then the yield-expression
1222 is equivalent to the expression co_await p.yield_value(e).
1223 build p.yield_value(e): */
1224 vec<tree, va_gc> *args = make_tree_vector_single (expr);
1225 tree yield_call
1226 = coro_build_promise_expression (current_function_decl, NULL,
1227 coro_yield_value_identifier, kw,
1228 &args, /*musthave=*/true);
1229 release_tree_vector (args);
1230
1231 /* Now build co_await p.yield_value (e).
1232 Noting that for co_yield, there is no evaluation of any potential
1233 promise transform_await(), so we call build_co_await directly. */
1234
1235 tree op = build_co_await (kw, yield_call, CO_YIELD_SUSPEND_POINT);
1236 if (op != error_mark_node)
1237 {
1238 if (REFERENCE_REF_P (op))
1239 op = TREE_OPERAND (op, 0);
1240 /* If the await expression is wrapped in a TARGET_EXPR, then transfer
1241 that wrapper to the CO_YIELD_EXPR, since this is just a proxy for
1242 its contained await. Otherwise, just build the CO_YIELD_EXPR. */
1243 if (TREE_CODE (op) == TARGET_EXPR)
1244 {
1245 tree t = TREE_OPERAND (op, 1);
1246 t = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (t), expr, t);
1247 TREE_OPERAND (op, 1) = t;
1248 }
1249 else
1250 op = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (op), expr, op);
1251 TREE_SIDE_EFFECTS (op) = 1;
1252 op = convert_from_reference (op);
1253 }
1254
1255 return op;
1256 }
1257
1258 /* Check and build a co_return statement.
1259 First that it's valid to have a co_return keyword here.
1260 If it is, then check and build the p.return_{void(),value(expr)}.
1261 These are built against a proxy for the promise, which will be filled
1262 in with the actual frame version when the function is transformed. */
1263
1264 tree
finish_co_return_stmt(location_t kw,tree expr)1265 finish_co_return_stmt (location_t kw, tree expr)
1266 {
1267 if (expr)
1268 STRIP_ANY_LOCATION_WRAPPER (expr);
1269
1270 if (error_operand_p (expr))
1271 return error_mark_node;
1272
1273 /* If it fails the following test, the function is not permitted to be a
1274 coroutine, so the co_return statement is erroneous. */
1275 if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
1276 "co_return"))
1277 return error_mark_node;
1278
1279 /* The current function has now become a coroutine, if it wasn't
1280 already. */
1281 DECL_COROUTINE_P (current_function_decl) = 1;
1282
1283 /* This function will appear to have no return statement, even if it
1284 is declared to return non-void (most likely). This is correct - we
1285 synthesize the return for the ramp in the compiler. So suppress any
1286 extraneous warnings during substitution. */
1287 TREE_NO_WARNING (current_function_decl) = true;
1288
1289 if (processing_template_decl
1290 && check_for_bare_parameter_packs (expr))
1291 return error_mark_node;
1292
1293 /* If we don't know the promise type, we can't proceed, build the
1294 co_return with the expression unchanged. */
1295 tree functype = TREE_TYPE (current_function_decl);
1296 if (dependent_type_p (functype) || type_dependent_expression_p (expr))
1297 {
1298 /* co_return expressions are always void type, regardless of the
1299 expression type. */
1300 expr = build2_loc (kw, CO_RETURN_EXPR, void_type_node,
1301 expr, NULL_TREE);
1302 expr = maybe_cleanup_point_expr_void (expr);
1303 return add_stmt (expr);
1304 }
1305
1306 if (!coro_promise_type_found_p (current_function_decl, kw))
1307 return error_mark_node;
1308
1309 /* Suppress -Wreturn-type for co_return, we need to check indirectly
1310 whether the promise type has a suitable return_void/return_value. */
1311 TREE_NO_WARNING (current_function_decl) = true;
1312
1313 if (!processing_template_decl && warn_sequence_point)
1314 verify_sequence_points (expr);
1315
1316 if (expr)
1317 {
1318 /* If we had an id-expression obfuscated by force_paren_expr, we need
1319 to undo it so we can try to treat it as an rvalue below. */
1320 expr = maybe_undo_parenthesized_ref (expr);
1321
1322 if (processing_template_decl)
1323 expr = build_non_dependent_expr (expr);
1324
1325 if (error_operand_p (expr))
1326 return error_mark_node;
1327 }
1328
1329 /* If the promise object doesn't have the correct return call then
1330 there's a mis-match between the co_return <expr> and this. */
1331 tree co_ret_call = error_mark_node;
1332 if (expr == NULL_TREE || VOID_TYPE_P (TREE_TYPE (expr)))
1333 co_ret_call
1334 = get_coroutine_return_void_expr (current_function_decl, kw, true);
1335 else
1336 {
1337 /* [class.copy.elision] / 3.
1338 An implicitly movable entity is a variable of automatic storage
1339 duration that is either a non-volatile object or an rvalue reference
1340 to a non-volatile object type. For such objects in the context of
1341 the co_return, the overload resolution should be carried out first
1342 treating the object as an rvalue, if that fails, then we fall back
1343 to regular overload resolution. */
1344
1345 tree arg = expr;
1346 if (tree moved = treat_lvalue_as_rvalue_p (expr, /*return*/true))
1347 arg = moved;
1348
1349 releasing_vec args = make_tree_vector_single (arg);
1350 co_ret_call
1351 = coro_build_promise_expression (current_function_decl, NULL,
1352 coro_return_value_identifier, kw,
1353 &args, /*musthave=*/true);
1354 }
1355
1356 /* Makes no sense for a co-routine really. */
1357 if (TREE_THIS_VOLATILE (current_function_decl))
1358 warning_at (kw, 0,
1359 "function declared %<noreturn%> has a"
1360 " %<co_return%> statement");
1361
1362 expr = build2_loc (kw, CO_RETURN_EXPR, void_type_node, expr, co_ret_call);
1363 expr = maybe_cleanup_point_expr_void (expr);
1364 return add_stmt (expr);
1365 }
1366
1367 /* We need to validate the arguments to __builtin_coro_promise, since the
1368 second two must be constant, and the builtins machinery doesn't seem to
1369 deal with that properly. */
1370
1371 tree
coro_validate_builtin_call(tree call,tsubst_flags_t)1372 coro_validate_builtin_call (tree call, tsubst_flags_t)
1373 {
1374 tree fn = TREE_OPERAND (CALL_EXPR_FN (call), 0);
1375
1376 gcc_checking_assert (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL);
1377 switch (DECL_FUNCTION_CODE (fn))
1378 {
1379 default:
1380 return call;
1381
1382 case BUILT_IN_CORO_PROMISE:
1383 {
1384 /* Argument 0 is already checked by the normal built-in machinery
1385 Argument 1 must be a constant of size type. It probably makes
1386 little sense if it's not a power of 2, but that isn't specified
1387 formally. */
1388 tree arg = CALL_EXPR_ARG (call, 1);
1389 location_t loc = EXPR_LOCATION (arg);
1390
1391 /* We expect alignof expressions in templates. */
1392 if (TREE_CODE (arg) == NON_DEPENDENT_EXPR
1393 && TREE_CODE (TREE_OPERAND (arg, 0)) == ALIGNOF_EXPR)
1394 ;
1395 else if (!TREE_CONSTANT (arg))
1396 {
1397 error_at (loc, "the align argument to %<__builtin_coro_promise%>"
1398 " must be a constant");
1399 return error_mark_node;
1400 }
1401 /* Argument 2 is the direction - to / from handle address to promise
1402 address. */
1403 arg = CALL_EXPR_ARG (call, 2);
1404 loc = EXPR_LOCATION (arg);
1405 if (!TREE_CONSTANT (arg))
1406 {
1407 error_at (loc, "the direction argument to"
1408 " %<__builtin_coro_promise%> must be a constant");
1409 return error_mark_node;
1410 }
1411 return call;
1412 break;
1413 }
1414 }
1415 }
1416
1417 /* ================= Morph and Expand. =================
1418
1419 The entry point here is morph_fn_to_coro () which is called from
1420 finish_function () when we have completed any template expansion.
1421
1422 This is preceded by helper functions that implement the phases below.
1423
1424 The process proceeds in four phases.
1425
1426 A Initial framing.
1427 The user's function body is wrapped in the initial and final suspend
1428 points and we begin building the coroutine frame.
1429 We build empty decls for the actor and destroyer functions at this
1430 time too.
1431 When exceptions are enabled, the user's function body will also be
1432 wrapped in a try-catch block with the catch invoking the promise
1433 class 'unhandled_exception' method.
1434
1435 B Analysis.
1436 The user's function body is analyzed to determine the suspend points,
1437 if any, and to capture local variables that might persist across such
1438 suspensions. In most cases, it is not necessary to capture compiler
1439 temporaries, since the tree-lowering nests the suspensions correctly.
1440 However, in the case of a captured reference, there is a lifetime
1441 extension to the end of the full expression - which can mean across a
1442 suspend point in which case it must be promoted to a frame variable.
1443
1444 At the conclusion of analysis, we have a conservative frame layout and
1445 maps of the local variables to their frame entry points.
1446
1447 C Build the ramp function.
1448 Carry out the allocation for the coroutine frame (NOTE; the actual size
1449 computation is deferred until late in the middle end to allow for future
1450 optimizations that will be allowed to elide unused frame entries).
1451 We build the return object.
1452
1453 D Build and expand the actor and destroyer function bodies.
1454 The destroyer is a trivial shim that sets a bit to indicate that the
1455 destroy dispatcher should be used and then calls into the actor.
1456
1457 The actor function is the implementation of the user's state machine.
1458 The current suspend point is noted in an index.
1459 Each suspend point is encoded as a pair of internal functions, one in
1460 the relevant dispatcher, and one representing the suspend point.
1461
1462 During this process, the user's local variables and the proxies for the
1463 self-handle and the promise class instance are re-written to their
1464 coroutine frame equivalents.
1465
1466 The complete bodies for the ramp, actor and destroy function are passed
1467 back to finish_function for folding and gimplification. */
1468
1469 /* Helpers to build EXPR_STMT and void-cast EXPR_STMT, common ops. */
1470
1471 static tree
coro_build_expr_stmt(tree expr,location_t loc)1472 coro_build_expr_stmt (tree expr, location_t loc)
1473 {
1474 return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr));
1475 }
1476
1477 static tree
coro_build_cvt_void_expr_stmt(tree expr,location_t loc)1478 coro_build_cvt_void_expr_stmt (tree expr, location_t loc)
1479 {
1480 tree t = build1 (CONVERT_EXPR, void_type_node, expr);
1481 return coro_build_expr_stmt (t, loc);
1482 }
1483
1484 /* Helpers for label creation:
1485 1. Create a named label in the specified context. */
1486
1487 static tree
create_anon_label_with_ctx(location_t loc,tree ctx)1488 create_anon_label_with_ctx (location_t loc, tree ctx)
1489 {
1490 tree lab = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node);
1491
1492 DECL_CONTEXT (lab) = ctx;
1493 DECL_ARTIFICIAL (lab) = true;
1494 DECL_IGNORED_P (lab) = true;
1495 TREE_USED (lab) = true;
1496 return lab;
1497 }
1498
1499 /* 2. Create a named label in the specified context. */
1500
1501 static tree
create_named_label_with_ctx(location_t loc,const char * name,tree ctx)1502 create_named_label_with_ctx (location_t loc, const char *name, tree ctx)
1503 {
1504 tree lab_id = get_identifier (name);
1505 tree lab = define_label (loc, lab_id);
1506 DECL_CONTEXT (lab) = ctx;
1507 DECL_ARTIFICIAL (lab) = true;
1508 TREE_USED (lab) = true;
1509 return lab;
1510 }
1511
1512 struct proxy_replace
1513 {
1514 tree from, to;
1515 };
1516
1517 static tree
replace_proxy(tree * here,int * do_subtree,void * d)1518 replace_proxy (tree *here, int *do_subtree, void *d)
1519 {
1520 proxy_replace *data = (proxy_replace *) d;
1521
1522 if (*here == data->from)
1523 {
1524 *here = data->to;
1525 *do_subtree = 0;
1526 }
1527 else
1528 *do_subtree = 1;
1529 return NULL_TREE;
1530 }
1531
1532 /* Support for expansion of co_await statements. */
1533
1534 struct coro_aw_data
1535 {
1536 tree actor_fn; /* Decl for context. */
1537 tree coro_fp; /* Frame pointer var. */
1538 tree resume_idx; /* This is the index var in the frame. */
1539 tree i_a_r_c; /* initial suspend await_resume() was called if true. */
1540 tree self_h; /* This is a handle to the current coro (frame var). */
1541 tree cleanup; /* This is where to go once we complete local destroy. */
1542 tree cororet; /* This is where to go if we suspend. */
1543 tree corocont; /* This is where to go if we continue. */
1544 tree conthand; /* This is the handle for a continuation. */
1545 unsigned index; /* This is our current resume index. */
1546 };
1547
1548 /* Lightweight search for the first await expression in tree-walk order.
1549 returns:
1550 The first await expression found in STMT.
1551 NULL_TREE if there are none.
1552 So can be used to determine if the statement needs to be processed for
1553 awaits. */
1554
1555 static tree
co_await_find_in_subtree(tree * stmt,int *,void * d)1556 co_await_find_in_subtree (tree *stmt, int *, void *d)
1557 {
1558 tree **p = (tree **) d;
1559 if (TREE_CODE (*stmt) == CO_AWAIT_EXPR)
1560 {
1561 *p = stmt;
1562 return *stmt;
1563 }
1564 return NULL_TREE;
1565 }
1566
1567 /* Starting with a statement:
1568
1569 stmt => some tree containing one or more await expressions.
1570
1571 We replace the statement with:
1572 <STATEMENT_LIST> {
1573 initialize awaitable
1574 if (!ready)
1575 {
1576 suspension context.
1577 }
1578 resume:
1579 revised statement with one await expression rewritten to its
1580 await_resume() return value.
1581 }
1582
1583 We then recurse into the initializer and the revised statement
1584 repeating this replacement until there are no more await expressions
1585 in either. */
1586
1587 static tree *
expand_one_await_expression(tree * stmt,tree * await_expr,void * d)1588 expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
1589 {
1590 coro_aw_data *data = (coro_aw_data *) d;
1591
1592 tree saved_statement = *stmt;
1593 tree saved_co_await = *await_expr;
1594
1595 tree actor = data->actor_fn;
1596 location_t loc = EXPR_LOCATION (*stmt);
1597 tree var = TREE_OPERAND (saved_co_await, 1); /* frame slot. */
1598 tree expr = TREE_OPERAND (saved_co_await, 2); /* initializer. */
1599 tree awaiter_calls = TREE_OPERAND (saved_co_await, 3);
1600
1601 tree source = TREE_OPERAND (saved_co_await, 4);
1602 bool is_final = (source
1603 && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT);
1604 bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var));
1605 int resume_point = data->index;
1606 size_t bufsize = sizeof ("destroy.") + 10;
1607 char *buf = (char *) alloca (bufsize);
1608 snprintf (buf, bufsize, "destroy.%d", resume_point);
1609 tree destroy_label = create_named_label_with_ctx (loc, buf, actor);
1610 snprintf (buf, bufsize, "resume.%d", resume_point);
1611 tree resume_label = create_named_label_with_ctx (loc, buf, actor);
1612 tree empty_list = build_empty_stmt (loc);
1613
1614 tree await_type = TREE_TYPE (var);
1615 tree stmt_list = NULL;
1616 tree r;
1617 tree *await_init = NULL;
1618
1619 if (!expr)
1620 needs_dtor = false; /* No need, the var's lifetime is managed elsewhere. */
1621 else
1622 {
1623 r = coro_build_cvt_void_expr_stmt (expr, loc);
1624 append_to_statement_list_force (r, &stmt_list);
1625 /* We have an initializer, which might itself contain await exprs. */
1626 await_init = tsi_stmt_ptr (tsi_last (stmt_list));
1627 }
1628
1629 /* Use the await_ready() call to test if we need to suspend. */
1630 tree ready_cond = TREE_VEC_ELT (awaiter_calls, 0); /* await_ready(). */
1631 /* Convert to bool, if necessary. */
1632 if (TREE_CODE (TREE_TYPE (ready_cond)) != BOOLEAN_TYPE)
1633 ready_cond = cp_convert (boolean_type_node, ready_cond,
1634 tf_warning_or_error);
1635 /* Be aggressive in folding here, since there are a significant number of
1636 cases where the ready condition is constant. */
1637 ready_cond = invert_truthvalue_loc (loc, ready_cond);
1638 ready_cond
1639 = build1_loc (loc, CLEANUP_POINT_EXPR, boolean_type_node, ready_cond);
1640
1641 tree body_list = NULL;
1642 tree susp_idx = build_int_cst (short_unsigned_type_node, data->index);
1643 r = build2_loc (loc, MODIFY_EXPR, short_unsigned_type_node, data->resume_idx,
1644 susp_idx);
1645 r = coro_build_cvt_void_expr_stmt (r, loc);
1646 append_to_statement_list (r, &body_list);
1647
1648 /* Find out what we have to do with the awaiter's suspend method.
1649 [expr.await]
1650 (5.1) If the result of await-ready is false, the coroutine is considered
1651 suspended. Then:
1652 (5.1.1) If the type of await-suspend is std::coroutine_handle<Z>,
1653 await-suspend.resume() is evaluated.
1654 (5.1.2) if the type of await-suspend is bool, await-suspend is evaluated,
1655 and the coroutine is resumed if the result is false.
1656 (5.1.3) Otherwise, await-suspend is evaluated. */
1657
1658 tree suspend = TREE_VEC_ELT (awaiter_calls, 1); /* await_suspend(). */
1659 tree susp_type = TREE_TYPE (suspend);
1660
1661 bool is_cont = false;
1662 /* NOTE: final suspend can't resume; the "resume" label in that case
1663 corresponds to implicit destruction. */
1664 if (VOID_TYPE_P (susp_type))
1665 {
1666 /* We just call await_suspend() and hit the yield. */
1667 suspend = coro_build_cvt_void_expr_stmt (suspend, loc);
1668 append_to_statement_list (suspend, &body_list);
1669 }
1670 else if (TREE_CODE (susp_type) == BOOLEAN_TYPE)
1671 {
1672 /* Boolean return, continue if the call returns false. */
1673 suspend = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, suspend);
1674 suspend
1675 = build1_loc (loc, CLEANUP_POINT_EXPR, boolean_type_node, suspend);
1676 tree go_on = build1_loc (loc, GOTO_EXPR, void_type_node, resume_label);
1677 r = build3_loc (loc, COND_EXPR, void_type_node, suspend, go_on,
1678 empty_list);
1679 append_to_statement_list (r, &body_list);
1680 }
1681 else
1682 {
1683 r = build1_loc (loc, CONVERT_EXPR, void_coro_handle_type, suspend);
1684 r = build2_loc (loc, INIT_EXPR, void_coro_handle_type, data->conthand, r);
1685 r = build1 (CONVERT_EXPR, void_type_node, r);
1686 append_to_statement_list (r, &body_list);
1687 is_cont = true;
1688 }
1689
1690 tree d_l = build_address (destroy_label);
1691 tree r_l = build_address (resume_label);
1692 tree susp = build_address (data->cororet);
1693 tree cont = build_address (data->corocont);
1694 tree final_susp = build_int_cst (integer_type_node, is_final ? 1 : 0);
1695
1696 susp_idx = build_int_cst (integer_type_node, data->index);
1697
1698 tree sw = begin_switch_stmt ();
1699 tree cond = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
1700 DECL_ARTIFICIAL (cond) = 1;
1701 DECL_IGNORED_P (cond) = 1;
1702 layout_decl (cond, 0);
1703
1704 r = build_call_expr_internal_loc (loc, IFN_CO_YIELD, integer_type_node, 5,
1705 susp_idx, final_susp, r_l, d_l,
1706 data->coro_fp);
1707 r = build2 (INIT_EXPR, integer_type_node, cond, r);
1708 finish_switch_cond (r, sw);
1709 r = build_case_label (build_int_cst (integer_type_node, 0), NULL_TREE,
1710 create_anon_label_with_ctx (loc, actor));
1711 add_stmt (r); /* case 0: */
1712 /* Implement the suspend, a scope exit without clean ups. */
1713 r = build_call_expr_internal_loc (loc, IFN_CO_SUSPN, void_type_node, 1,
1714 is_cont ? cont : susp);
1715 r = coro_build_cvt_void_expr_stmt (r, loc);
1716 add_stmt (r); /* goto ret; */
1717 r = build_case_label (build_int_cst (integer_type_node, 1), NULL_TREE,
1718 create_anon_label_with_ctx (loc, actor));
1719 add_stmt (r); /* case 1: */
1720 r = build1_loc (loc, GOTO_EXPR, void_type_node, resume_label);
1721 add_stmt (r); /* goto resume; */
1722 r = build_case_label (NULL_TREE, NULL_TREE,
1723 create_anon_label_with_ctx (loc, actor));
1724 add_stmt (r); /* default:; */
1725 r = build1_loc (loc, GOTO_EXPR, void_type_node, destroy_label);
1726 add_stmt (r); /* goto destroy; */
1727
1728 /* part of finish switch. */
1729 SWITCH_STMT_BODY (sw) = pop_stmt_list (SWITCH_STMT_BODY (sw));
1730 pop_switch ();
1731 tree scope = SWITCH_STMT_SCOPE (sw);
1732 SWITCH_STMT_SCOPE (sw) = NULL;
1733 r = do_poplevel (scope);
1734 append_to_statement_list (r, &body_list);
1735
1736 destroy_label = build_stmt (loc, LABEL_EXPR, destroy_label);
1737 append_to_statement_list (destroy_label, &body_list);
1738 if (needs_dtor)
1739 {
1740 tree dtor = build_special_member_call (var, complete_dtor_identifier,
1741 NULL, await_type, LOOKUP_NORMAL,
1742 tf_warning_or_error);
1743 append_to_statement_list (dtor, &body_list);
1744 }
1745 r = build1_loc (loc, GOTO_EXPR, void_type_node, data->cleanup);
1746 append_to_statement_list (r, &body_list);
1747
1748 r = build3_loc (loc, COND_EXPR, void_type_node, ready_cond, body_list,
1749 empty_list);
1750
1751 append_to_statement_list (r, &stmt_list);
1752
1753 /* Resume point. */
1754 resume_label = build_stmt (loc, LABEL_EXPR, resume_label);
1755 append_to_statement_list (resume_label, &stmt_list);
1756
1757 /* This will produce the value (if one is provided) from the co_await
1758 expression. */
1759 tree resume_call = TREE_VEC_ELT (awaiter_calls, 2); /* await_resume(). */
1760 if (REFERENCE_REF_P (resume_call))
1761 /* Sink to await_resume call_expr. */
1762 resume_call = TREE_OPERAND (resume_call, 0);
1763
1764 *await_expr = resume_call; /* Replace the co_await expr with its result. */
1765 append_to_statement_list_force (saved_statement, &stmt_list);
1766 /* Get a pointer to the revised statement. */
1767 tree *revised = tsi_stmt_ptr (tsi_last (stmt_list));
1768 if (needs_dtor)
1769 {
1770 tree dtor = build_special_member_call (var, complete_dtor_identifier,
1771 NULL, await_type, LOOKUP_NORMAL,
1772 tf_warning_or_error);
1773 append_to_statement_list (dtor, &stmt_list);
1774 }
1775 data->index += 2;
1776
1777 /* Replace the original statement with the expansion. */
1778 *stmt = stmt_list;
1779
1780 /* Now, if the awaitable had an initializer, expand any awaits that might
1781 be embedded in it. */
1782 tree *aw_expr_ptr;
1783 if (await_init &&
1784 cp_walk_tree (await_init, co_await_find_in_subtree, &aw_expr_ptr, NULL))
1785 expand_one_await_expression (await_init, aw_expr_ptr, d);
1786
1787 /* Expand any more await expressions in the the original statement. */
1788 if (cp_walk_tree (revised, co_await_find_in_subtree, &aw_expr_ptr, NULL))
1789 expand_one_await_expression (revised, aw_expr_ptr, d);
1790
1791 return NULL;
1792 }
1793
1794 /* Check to see if a statement contains at least one await expression, if
1795 so, then process that. */
1796
1797 static tree
process_one_statement(tree * stmt,void * d)1798 process_one_statement (tree *stmt, void *d)
1799 {
1800 tree *aw_expr_ptr;
1801 if (cp_walk_tree (stmt, co_await_find_in_subtree, &aw_expr_ptr, NULL))
1802 expand_one_await_expression (stmt, aw_expr_ptr, d);
1803 return NULL_TREE;
1804 }
1805
1806 static tree
await_statement_expander(tree * stmt,int * do_subtree,void * d)1807 await_statement_expander (tree *stmt, int *do_subtree, void *d)
1808 {
1809 tree res = NULL_TREE;
1810
1811 /* Process a statement at a time. */
1812 if (STATEMENT_CLASS_P (*stmt) || TREE_CODE (*stmt) == BIND_EXPR)
1813 return NULL_TREE; /* Just process the sub-trees. */
1814 else if (TREE_CODE (*stmt) == STATEMENT_LIST)
1815 {
1816 tree_stmt_iterator i;
1817 for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i))
1818 {
1819 res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_expander,
1820 d, NULL);
1821 if (res)
1822 return res;
1823 }
1824 *do_subtree = 0; /* Done subtrees. */
1825 }
1826 else if (EXPR_P (*stmt))
1827 {
1828 process_one_statement (stmt, d);
1829 *do_subtree = 0; /* Done subtrees. */
1830 }
1831
1832 /* Continue statement walk, where required. */
1833 return res;
1834 }
1835
1836 /* Suspend point hash_map. */
1837
1838 struct suspend_point_info
1839 {
1840 /* coro frame field type. */
1841 tree awaitable_type;
1842 /* coro frame field name. */
1843 tree await_field_id;
1844 };
1845
1846 static hash_map<tree, suspend_point_info> *suspend_points;
1847
1848 struct await_xform_data
1849 {
1850 tree actor_fn; /* Decl for context. */
1851 tree actor_frame;
1852 tree promise_proxy;
1853 tree real_promise;
1854 tree self_h_proxy;
1855 tree real_self_h;
1856 };
1857
1858 /* When we built the await expressions, we didn't know the coro frame
1859 layout, therefore no idea where to find the promise or where to put
1860 the awaitables. Now we know these things, fill them in. */
1861
1862 static tree
transform_await_expr(tree await_expr,await_xform_data * xform)1863 transform_await_expr (tree await_expr, await_xform_data *xform)
1864 {
1865 suspend_point_info *si = suspend_points->get (await_expr);
1866 location_t loc = EXPR_LOCATION (await_expr);
1867 if (!si)
1868 {
1869 error_at (loc, "no suspend point info for %qD", await_expr);
1870 return error_mark_node;
1871 }
1872
1873 /* So, on entry, we have:
1874 in : CO_AWAIT_EXPR (a, e_proxy, o, awr_call_vector, mode)
1875 We no longer need a [it had diagnostic value, maybe?]
1876 We need to replace the promise proxy in all elements
1877 We need to replace the e_proxy in the awr_call. */
1878
1879 tree coro_frame_type = TREE_TYPE (xform->actor_frame);
1880
1881 /* If we have a frame var for the awaitable, get a reference to it. */
1882 proxy_replace data;
1883 if (si->await_field_id)
1884 {
1885 tree as_m
1886 = lookup_member (coro_frame_type, si->await_field_id,
1887 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
1888 tree as = build_class_member_access_expr (xform->actor_frame, as_m,
1889 NULL_TREE, true,
1890 tf_warning_or_error);
1891
1892 /* Replace references to the instance proxy with the frame entry now
1893 computed. */
1894 data.from = TREE_OPERAND (await_expr, 1);
1895 data.to = as;
1896 cp_walk_tree (&await_expr, replace_proxy, &data, NULL);
1897
1898 /* .. and replace. */
1899 TREE_OPERAND (await_expr, 1) = as;
1900 }
1901
1902 /* Now do the self_handle. */
1903 data.from = xform->self_h_proxy;
1904 data.to = xform->real_self_h;
1905 cp_walk_tree (&await_expr, replace_proxy, &data, NULL);
1906
1907 /* Now do the promise. */
1908 data.from = xform->promise_proxy;
1909 data.to = xform->real_promise;
1910 cp_walk_tree (&await_expr, replace_proxy, &data, NULL);
1911
1912 return await_expr;
1913 }
1914
1915 /* A wrapper for the transform_await_expr function so that it can be a
1916 callback from cp_walk_tree. */
1917
1918 static tree
transform_await_wrapper(tree * stmt,int * do_subtree,void * d)1919 transform_await_wrapper (tree *stmt, int *do_subtree, void *d)
1920 {
1921 /* Set actor function as new DECL_CONTEXT of label_decl. */
1922 struct await_xform_data *xform = (struct await_xform_data *) d;
1923 if (TREE_CODE (*stmt) == LABEL_DECL
1924 && DECL_CONTEXT (*stmt) != xform->actor_fn)
1925 DECL_CONTEXT (*stmt) = xform->actor_fn;
1926
1927 /* We should have already lowered co_yields to their co_await. */
1928 gcc_checking_assert (TREE_CODE (*stmt) != CO_YIELD_EXPR);
1929 if (TREE_CODE (*stmt) != CO_AWAIT_EXPR)
1930 return NULL_TREE;
1931
1932 tree await_expr = *stmt;
1933 *stmt = transform_await_expr (await_expr, xform);
1934 if (*stmt == error_mark_node)
1935 *do_subtree = 0;
1936 return NULL_TREE;
1937 }
1938
1939 /* This caches information that we determine about function params,
1940 their uses and copies in the coroutine frame. */
1941
1942 struct param_info
1943 {
1944 tree field_id; /* The name of the copy in the coroutine frame. */
1945 vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */
1946 tree frame_type; /* The type used to represent this parm in the frame. */
1947 tree orig_type; /* The original type of the parm (not as passed). */
1948 tree guard_var; /* If we need a DTOR on exception, this bool guards it. */
1949 tree fr_copy_dtor; /* If we need a DTOR on exception, this is it. */
1950 bool by_ref; /* Was passed by reference. */
1951 bool pt_ref; /* Was a pointer to object. */
1952 bool rv_ref; /* Was an rvalue ref. */
1953 bool trivial_dtor; /* The frame type has a trivial DTOR. */
1954 bool this_ptr; /* Is 'this' */
1955 bool lambda_cobj; /* Lambda capture object */
1956 };
1957
1958 struct local_var_info
1959 {
1960 tree field_id;
1961 tree field_idx;
1962 tree frame_type;
1963 bool is_lambda_capture;
1964 bool is_static;
1965 bool has_value_expr_p;
1966 location_t def_loc;
1967 };
1968
1969 /* For figuring out what local variable usage we have. */
1970 struct local_vars_transform
1971 {
1972 tree context;
1973 tree actor_frame;
1974 tree coro_frame_type;
1975 location_t loc;
1976 hash_map<tree, local_var_info> *local_var_uses;
1977 };
1978
1979 static tree
transform_local_var_uses(tree * stmt,int * do_subtree,void * d)1980 transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
1981 {
1982 local_vars_transform *lvd = (local_vars_transform *) d;
1983
1984 /* For each var in this bind expr (that has a frame id, which means it was
1985 accessed), build a frame reference for each and then walk the bind expr
1986 statements, substituting the frame ref for the original var. */
1987
1988 if (TREE_CODE (*stmt) == BIND_EXPR)
1989 {
1990 tree lvar;
1991 for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL;
1992 lvar = DECL_CHAIN (lvar))
1993 {
1994 bool existed;
1995 local_var_info &local_var
1996 = lvd->local_var_uses->get_or_insert (lvar, &existed);
1997 gcc_checking_assert (existed);
1998
1999 /* Re-write the variable's context to be in the actor func. */
2000 DECL_CONTEXT (lvar) = lvd->context;
2001
2002 /* For capture proxies, this could include the decl value expr. */
2003 if (local_var.is_lambda_capture || local_var.has_value_expr_p)
2004 {
2005 tree ve = DECL_VALUE_EXPR (lvar);
2006 cp_walk_tree (&ve, transform_local_var_uses, d, NULL);
2007 continue; /* No frame entry for this. */
2008 }
2009
2010 /* TODO: implement selective generation of fields when vars are
2011 known not-used. */
2012 if (local_var.field_id == NULL_TREE)
2013 continue; /* Wasn't used. */
2014
2015 tree fld_ref
2016 = lookup_member (lvd->coro_frame_type, local_var.field_id,
2017 /*protect=*/1, /*want_type=*/0,
2018 tf_warning_or_error);
2019 tree fld_idx = build3_loc (lvd->loc, COMPONENT_REF, TREE_TYPE (lvar),
2020 lvd->actor_frame, fld_ref, NULL_TREE);
2021 local_var.field_idx = fld_idx;
2022 }
2023 /* FIXME: we should be able to do this in the loop above, but (at least
2024 for range for) there are cases where the DECL_INITIAL contains
2025 forward references.
2026 So, now we've built the revised var in the frame, substitute uses of
2027 it in initializers and the bind expr body. */
2028 for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL;
2029 lvar = DECL_CHAIN (lvar))
2030 {
2031 /* we need to walk some of the decl trees, which might contain
2032 references to vars replaced at a higher level. */
2033 cp_walk_tree (&DECL_INITIAL (lvar), transform_local_var_uses, d,
2034 NULL);
2035 cp_walk_tree (&DECL_SIZE (lvar), transform_local_var_uses, d, NULL);
2036 cp_walk_tree (&DECL_SIZE_UNIT (lvar), transform_local_var_uses, d,
2037 NULL);
2038 }
2039 cp_walk_tree (&BIND_EXPR_BODY (*stmt), transform_local_var_uses, d, NULL);
2040
2041 /* Now we have processed and removed references to the original vars,
2042 we can drop those from the bind - leaving capture proxies alone. */
2043 for (tree *pvar = &BIND_EXPR_VARS (*stmt); *pvar != NULL;)
2044 {
2045 bool existed;
2046 local_var_info &local_var
2047 = lvd->local_var_uses->get_or_insert (*pvar, &existed);
2048 gcc_checking_assert (existed);
2049
2050 /* Leave lambda closure captures alone, we replace the *this
2051 pointer with the frame version and let the normal process
2052 deal with the rest.
2053 Likewise, variables with their value found elsewhere.
2054 Skip past unused ones too. */
2055 if (local_var.is_lambda_capture
2056 || local_var.has_value_expr_p
2057 || local_var.field_id == NULL_TREE)
2058 {
2059 pvar = &DECL_CHAIN (*pvar);
2060 continue;
2061 }
2062
2063 /* Discard this one, we replaced it. */
2064 *pvar = DECL_CHAIN (*pvar);
2065 }
2066
2067 *do_subtree = 0; /* We've done the body already. */
2068 return NULL_TREE;
2069 }
2070
2071 tree var_decl = *stmt;
2072 /* Look inside cleanups, we don't want to wrap a statement list in a
2073 cleanup. */
2074 bool needs_cleanup = true;
2075 if (TREE_CODE (var_decl) == CLEANUP_POINT_EXPR)
2076 var_decl = TREE_OPERAND (var_decl, 0);
2077 else
2078 needs_cleanup = false;
2079
2080 /* Look inside the decl_expr for the actual var. */
2081 bool decl_expr_p = TREE_CODE (var_decl) == DECL_EXPR;
2082 if (decl_expr_p && TREE_CODE (DECL_EXPR_DECL (var_decl)) == VAR_DECL)
2083 var_decl = DECL_EXPR_DECL (var_decl);
2084 else if (TREE_CODE (var_decl) != VAR_DECL)
2085 return NULL_TREE;
2086
2087 /* VAR_DECLs that are not recorded can belong to the proxies we've placed
2088 for the promise and coroutine handle(s), to global vars or to compiler
2089 temporaries. Skip past these, we will handle them later. */
2090 local_var_info *local_var_i = lvd->local_var_uses->get (var_decl);
2091
2092 if (local_var_i == NULL)
2093 return NULL_TREE;
2094
2095 if (local_var_i->is_lambda_capture
2096 || local_var_i->is_static
2097 || local_var_i->has_value_expr_p)
2098 return NULL_TREE;
2099
2100 /* This is our revised 'local' i.e. a frame slot. */
2101 tree revised = local_var_i->field_idx;
2102 gcc_checking_assert (DECL_CONTEXT (var_decl) == lvd->context);
2103
2104 if (decl_expr_p && DECL_INITIAL (var_decl))
2105 {
2106 location_t loc = DECL_SOURCE_LOCATION (var_decl);
2107 tree r
2108 = cp_build_modify_expr (loc, revised, INIT_EXPR,
2109 DECL_INITIAL (var_decl), tf_warning_or_error);
2110 if (needs_cleanup)
2111 r = coro_build_cvt_void_expr_stmt (r, EXPR_LOCATION (*stmt));
2112 *stmt = r;
2113 }
2114 else
2115 *stmt = revised;
2116
2117 if (decl_expr_p)
2118 *do_subtree = 0; /* We've accounted for the nested use. */
2119 return NULL_TREE;
2120 }
2121
2122 /* A helper to build the frame DTOR.
2123 [dcl.fct.def.coroutine] / 12
2124 The deallocation function’s name is looked up in the scope of the promise
2125 type. If this lookup fails, the deallocation function’s name is looked up
2126 in the global scope. If deallocation function lookup finds both a usual
2127 deallocation function with only a pointer parameter and a usual
2128 deallocation function with both a pointer parameter and a size parameter,
2129 then the selected deallocation function shall be the one with two
2130 parameters. Otherwise, the selected deallocation function shall be the
2131 function with one parameter. If no usual deallocation function is found
2132 the program is ill-formed. The selected deallocation function shall be
2133 called with the address of the block of storage to be reclaimed as its
2134 first argument. If a deallocation function with a parameter of type
2135 std::size_t is used, the size of the block is passed as the corresponding
2136 argument. */
2137
2138 static tree
coro_get_frame_dtor(tree coro_fp,tree orig,tree frame_size,tree promise_type,location_t loc)2139 coro_get_frame_dtor (tree coro_fp, tree orig, tree frame_size,
2140 tree promise_type, location_t loc)
2141 {
2142 tree del_coro_fr = NULL_TREE;
2143 tree frame_arg = build1 (CONVERT_EXPR, ptr_type_node, coro_fp);
2144 tree delname = ovl_op_identifier (false, DELETE_EXPR);
2145 tree fns = lookup_promise_method (orig, delname, loc,
2146 /*musthave=*/false);
2147 if (fns && BASELINK_P (fns))
2148 {
2149 /* Look for sized version first, since this takes precedence. */
2150 vec<tree, va_gc> *args = make_tree_vector ();
2151 vec_safe_push (args, frame_arg);
2152 vec_safe_push (args, frame_size);
2153 tree dummy_promise = build_dummy_object (promise_type);
2154
2155 /* It's OK to fail for this one... */
2156 del_coro_fr = build_new_method_call (dummy_promise, fns, &args,
2157 NULL_TREE, LOOKUP_NORMAL, NULL,
2158 tf_none);
2159
2160 if (!del_coro_fr || del_coro_fr == error_mark_node)
2161 {
2162 release_tree_vector (args);
2163 args = make_tree_vector_single (frame_arg);
2164 del_coro_fr = build_new_method_call (dummy_promise, fns, &args,
2165 NULL_TREE, LOOKUP_NORMAL, NULL,
2166 tf_none);
2167 }
2168
2169 /* But one of them must succeed, or the program is ill-formed. */
2170 if (!del_coro_fr || del_coro_fr == error_mark_node)
2171 {
2172 error_at (loc, "%qE is provided by %qT but is not usable with"
2173 " the function signature %qD", delname, promise_type, orig);
2174 del_coro_fr = error_mark_node;
2175 }
2176 }
2177 else
2178 {
2179 del_coro_fr = build_op_delete_call (DELETE_EXPR, frame_arg, frame_size,
2180 /*global_p=*/true, /*placement=*/NULL,
2181 /*alloc_fn=*/NULL,
2182 tf_warning_or_error);
2183 if (!del_coro_fr || del_coro_fr == error_mark_node)
2184 del_coro_fr = error_mark_node;
2185 }
2186 return del_coro_fr;
2187 }
2188
2189 /* The actor transform. */
2190
2191 static void
build_actor_fn(location_t loc,tree coro_frame_type,tree actor,tree fnbody,tree orig,hash_map<tree,param_info> * param_uses,hash_map<tree,local_var_info> * local_var_uses,vec<tree,va_gc> * param_dtor_list,tree resume_fn_field,tree resume_idx_field,unsigned body_count,tree frame_size)2192 build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
2193 tree orig, hash_map<tree, param_info> *param_uses,
2194 hash_map<tree, local_var_info> *local_var_uses,
2195 vec<tree, va_gc> *param_dtor_list, tree resume_fn_field,
2196 tree resume_idx_field, unsigned body_count, tree frame_size)
2197 {
2198 verify_stmt_tree (fnbody);
2199 /* Some things we inherit from the original function. */
2200 tree handle_type = get_coroutine_handle_type (orig);
2201 tree self_h_proxy = get_coroutine_self_handle_proxy (orig);
2202 tree promise_type = get_coroutine_promise_type (orig);
2203 tree promise_proxy = get_coroutine_promise_proxy (orig);
2204
2205 /* One param, the coro frame pointer. */
2206 tree actor_fp = DECL_ARGUMENTS (actor);
2207
2208 /* We have a definition here. */
2209 TREE_STATIC (actor) = 1;
2210
2211 tree actor_outer = push_stmt_list ();
2212 current_stmt_tree ()->stmts_are_full_exprs_p = 1;
2213 tree stmt = begin_compound_stmt (BCS_FN_BODY);
2214
2215 tree actor_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
2216 tree top_block = make_node (BLOCK);
2217 BIND_EXPR_BLOCK (actor_bind) = top_block;
2218
2219 tree continuation = build_lang_decl (VAR_DECL,
2220 get_identifier ("actor.continue"),
2221 void_coro_handle_type);
2222 DECL_ARTIFICIAL (continuation) = 1;
2223 DECL_IGNORED_P (continuation) = 1;
2224 DECL_CONTEXT (continuation) = actor;
2225 BIND_EXPR_VARS (actor_bind) = continuation;
2226
2227 /* Link in the block associated with the outer scope of the re-written
2228 function body. */
2229 tree first = expr_first (fnbody);
2230 gcc_checking_assert (first && TREE_CODE (first) == BIND_EXPR);
2231 tree block = BIND_EXPR_BLOCK (first);
2232 gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
2233 gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE);
2234 BLOCK_SUPERCONTEXT (block) = top_block;
2235 BLOCK_SUBBLOCKS (top_block) = block;
2236
2237 add_stmt (actor_bind);
2238 tree actor_body = push_stmt_list ();
2239
2240 /* The entry point for the actor code from the ramp. */
2241 tree actor_begin_label
2242 = create_named_label_with_ctx (loc, "actor.begin", actor);
2243 tree actor_frame = build1_loc (loc, INDIRECT_REF, coro_frame_type, actor_fp);
2244
2245 /* Declare the continuation handle. */
2246 add_decl_expr (continuation);
2247
2248 /* Re-write param references in the body, no code should be generated
2249 here. */
2250 if (DECL_ARGUMENTS (orig))
2251 {
2252 tree arg;
2253 for (arg = DECL_ARGUMENTS (orig); arg != NULL; arg = DECL_CHAIN (arg))
2254 {
2255 bool existed;
2256 param_info &parm = param_uses->get_or_insert (arg, &existed);
2257 if (!parm.body_uses)
2258 continue; /* Wasn't used in the original function body. */
2259
2260 tree fld_ref = lookup_member (coro_frame_type, parm.field_id,
2261 /*protect=*/1, /*want_type=*/0,
2262 tf_warning_or_error);
2263 tree fld_idx = build3_loc (loc, COMPONENT_REF, parm.frame_type,
2264 actor_frame, fld_ref, NULL_TREE);
2265
2266 /* We keep these in the frame as a regular pointer, so convert that
2267 back to the type expected. */
2268 if (parm.pt_ref)
2269 fld_idx = build1_loc (loc, CONVERT_EXPR, TREE_TYPE (arg), fld_idx);
2270
2271 int i;
2272 tree *puse;
2273 FOR_EACH_VEC_ELT (*parm.body_uses, i, puse)
2274 *puse = fld_idx;
2275 }
2276 }
2277
2278 /* Re-write local vars, similarly. */
2279 local_vars_transform xform_vars_data
2280 = {actor, actor_frame, coro_frame_type, loc, local_var_uses};
2281 cp_walk_tree (&fnbody, transform_local_var_uses, &xform_vars_data, NULL);
2282
2283 tree resume_idx_name = get_identifier ("__resume_at");
2284 tree rat_field = lookup_member (coro_frame_type, resume_idx_name, 1, 0,
2285 tf_warning_or_error);
2286 tree rat = build3 (COMPONENT_REF, short_unsigned_type_node, actor_frame,
2287 rat_field, NULL_TREE);
2288
2289 tree ret_label
2290 = create_named_label_with_ctx (loc, "actor.suspend.ret", actor);
2291
2292 tree continue_label
2293 = create_named_label_with_ctx (loc, "actor.continue.ret", actor);
2294
2295 tree lsb_if = begin_if_stmt ();
2296 tree chkb0 = build2 (BIT_AND_EXPR, short_unsigned_type_node, rat,
2297 build_int_cst (short_unsigned_type_node, 1));
2298 chkb0 = build2 (NE_EXPR, short_unsigned_type_node, chkb0,
2299 build_int_cst (short_unsigned_type_node, 0));
2300 finish_if_stmt_cond (chkb0, lsb_if);
2301
2302 tree destroy_dispatcher = begin_switch_stmt ();
2303 finish_switch_cond (rat, destroy_dispatcher);
2304 tree ddeflab = build_case_label (NULL_TREE, NULL_TREE,
2305 create_anon_label_with_ctx (loc, actor));
2306 add_stmt (ddeflab);
2307 tree b = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
2308 b = coro_build_cvt_void_expr_stmt (b, loc);
2309 add_stmt (b);
2310
2311 /* The destroy point numbered #1 is special, in that it is reached from a
2312 coroutine that is suspended after re-throwing from unhandled_exception().
2313 This label just invokes the cleanup of promise, param copies and the
2314 frame itself. */
2315 tree del_promise_label
2316 = create_named_label_with_ctx (loc, "coro.delete.promise", actor);
2317 b = build_case_label (build_int_cst (short_unsigned_type_node, 1), NULL_TREE,
2318 create_anon_label_with_ctx (loc, actor));
2319 add_stmt (b);
2320 add_stmt (build_stmt (loc, GOTO_EXPR, del_promise_label));
2321
2322 short unsigned lab_num = 3;
2323 for (unsigned destr_pt = 0; destr_pt < body_count; destr_pt++)
2324 {
2325 tree l_num = build_int_cst (short_unsigned_type_node, lab_num);
2326 b = build_case_label (l_num, NULL_TREE,
2327 create_anon_label_with_ctx (loc, actor));
2328 add_stmt (b);
2329 b = build_call_expr_internal_loc (loc, IFN_CO_ACTOR, void_type_node, 1,
2330 l_num);
2331 b = coro_build_cvt_void_expr_stmt (b, loc);
2332 add_stmt (b);
2333 b = build1 (GOTO_EXPR, void_type_node, CASE_LABEL (ddeflab));
2334 add_stmt (b);
2335 lab_num += 2;
2336 }
2337
2338 /* Insert the prototype dispatcher. */
2339 finish_switch_stmt (destroy_dispatcher);
2340
2341 finish_then_clause (lsb_if);
2342
2343 tree dispatcher = begin_switch_stmt ();
2344 finish_switch_cond (rat, dispatcher);
2345 b = build_case_label (build_int_cst (short_unsigned_type_node, 0), NULL_TREE,
2346 create_anon_label_with_ctx (loc, actor));
2347 add_stmt (b);
2348 b = build1 (GOTO_EXPR, void_type_node, actor_begin_label);
2349 add_stmt (b);
2350
2351 tree rdeflab = build_case_label (NULL_TREE, NULL_TREE,
2352 create_anon_label_with_ctx (loc, actor));
2353 add_stmt (rdeflab);
2354 b = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
2355 b = coro_build_cvt_void_expr_stmt (b, loc);
2356 add_stmt (b);
2357
2358 lab_num = 2;
2359 /* The final resume should be made to hit the default (trap, UB) entry
2360 although it will be unreachable via the normal entry point, since that
2361 is set to NULL on reaching final suspend. */
2362 for (unsigned resu_pt = 0; resu_pt < body_count; resu_pt++)
2363 {
2364 tree l_num = build_int_cst (short_unsigned_type_node, lab_num);
2365 b = build_case_label (l_num, NULL_TREE,
2366 create_anon_label_with_ctx (loc, actor));
2367 add_stmt (b);
2368 b = build_call_expr_internal_loc (loc, IFN_CO_ACTOR, void_type_node, 1,
2369 l_num);
2370 b = coro_build_cvt_void_expr_stmt (b, loc);
2371 add_stmt (b);
2372 b = build1 (GOTO_EXPR, void_type_node, CASE_LABEL (rdeflab));
2373 add_stmt (b);
2374 lab_num += 2;
2375 }
2376
2377 /* Insert the prototype dispatcher. */
2378 finish_switch_stmt (dispatcher);
2379
2380 finish_if_stmt (lsb_if);
2381
2382 tree r = build_stmt (loc, LABEL_EXPR, actor_begin_label);
2383 add_stmt (r);
2384
2385 /* actor's version of the promise. */
2386 tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0,
2387 tf_warning_or_error);
2388 tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE, false,
2389 tf_warning_or_error);
2390
2391 /* actor's coroutine 'self handle'. */
2392 tree ash_m = lookup_member (coro_frame_type, get_identifier ("__self_h"), 1,
2393 0, tf_warning_or_error);
2394 tree ash = build_class_member_access_expr (actor_frame, ash_m, NULL_TREE,
2395 false, tf_warning_or_error);
2396 /* So construct the self-handle from the frame address. */
2397 tree hfa_m = lookup_member (handle_type, coro_from_address_identifier, 1,
2398 0, tf_warning_or_error);
2399
2400 r = build1 (CONVERT_EXPR, build_pointer_type (void_type_node), actor_fp);
2401 vec<tree, va_gc> *args = make_tree_vector_single (r);
2402 tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL,
2403 NULL, tf_warning_or_error);
2404 r = build2 (INIT_EXPR, handle_type, ash, hfa);
2405 r = coro_build_cvt_void_expr_stmt (r, loc);
2406 add_stmt (r);
2407 release_tree_vector (args);
2408
2409 /* Now we know the real promise, and enough about the frame layout to
2410 decide where to put things. */
2411
2412 await_xform_data xform
2413 = {actor, actor_frame, promise_proxy, ap, self_h_proxy, ash};
2414
2415 /* Transform the await expressions in the function body. Only do each
2416 await tree once! */
2417 hash_set<tree> pset;
2418 cp_walk_tree (&fnbody, transform_await_wrapper, &xform, &pset);
2419
2420 /* Now replace the promise proxy with its real value. */
2421 proxy_replace p_data;
2422 p_data.from = promise_proxy;
2423 p_data.to = ap;
2424 cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL);
2425
2426 /* The rewrite of the function adds code to set the __resume field to
2427 nullptr when the coroutine is done and also the index to zero when
2428 calling an unhandled exception. These are represented by two proxies
2429 in the function, so rewrite them to the proper frame access. */
2430 tree resume_m
2431 = lookup_member (coro_frame_type, get_identifier ("__resume"),
2432 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
2433 tree res_x = build_class_member_access_expr (actor_frame, resume_m, NULL_TREE,
2434 false, tf_warning_or_error);
2435 p_data.from = resume_fn_field;
2436 p_data.to = res_x;
2437 cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL);
2438
2439 p_data.from = resume_idx_field;
2440 p_data.to = rat;
2441 cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL);
2442
2443 /* Add in our function body with the co_returns rewritten to final form. */
2444 add_stmt (fnbody);
2445
2446 /* now do the tail of the function. */
2447 r = build_stmt (loc, LABEL_EXPR, del_promise_label);
2448 add_stmt (r);
2449
2450 /* Destructors for the things we built explicitly. */
2451 r = build_special_member_call (ap, complete_dtor_identifier, NULL,
2452 promise_type, LOOKUP_NORMAL,
2453 tf_warning_or_error);
2454 add_stmt (r);
2455
2456 tree del_frame_label
2457 = create_named_label_with_ctx (loc, "coro.delete.frame", actor);
2458 r = build_stmt (loc, LABEL_EXPR, del_frame_label);
2459 add_stmt (r);
2460
2461 /* Here deallocate the frame (if we allocated it), which we will have at
2462 present. */
2463 tree fnf_m
2464 = lookup_member (coro_frame_type, get_identifier ("__frame_needs_free"), 1,
2465 0, tf_warning_or_error);
2466 tree fnf2_x = build_class_member_access_expr (actor_frame, fnf_m, NULL_TREE,
2467 false, tf_warning_or_error);
2468
2469 tree need_free_if = begin_if_stmt ();
2470 fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x);
2471 tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node);
2472 finish_if_stmt_cond (cmp, need_free_if);
2473 if (param_dtor_list != NULL)
2474 {
2475 int i;
2476 tree pid;
2477 FOR_EACH_VEC_ELT (*param_dtor_list, i, pid)
2478 {
2479 tree m
2480 = lookup_member (coro_frame_type, pid, 1, 0, tf_warning_or_error);
2481 tree a = build_class_member_access_expr (actor_frame, m, NULL_TREE,
2482 false, tf_warning_or_error);
2483 tree t = TREE_TYPE (a);
2484 tree dtor;
2485 dtor
2486 = build_special_member_call (a, complete_dtor_identifier, NULL, t,
2487 LOOKUP_NORMAL, tf_warning_or_error);
2488 add_stmt (dtor);
2489 }
2490 }
2491
2492 /* Build the frame DTOR. */
2493 tree del_coro_fr = coro_get_frame_dtor (actor_fp, orig, frame_size,
2494 promise_type, loc);
2495 finish_expr_stmt (del_coro_fr);
2496 finish_then_clause (need_free_if);
2497 tree scope = IF_SCOPE (need_free_if);
2498 IF_SCOPE (need_free_if) = NULL;
2499 r = do_poplevel (scope);
2500 add_stmt (r);
2501
2502 /* done. */
2503 r = build_stmt (loc, RETURN_EXPR, NULL);
2504 TREE_NO_WARNING (r) |= 1; /* We don't want a warning about this. */
2505 r = maybe_cleanup_point_expr_void (r);
2506 add_stmt (r);
2507
2508 /* This is the suspend return point. */
2509 r = build_stmt (loc, LABEL_EXPR, ret_label);
2510 add_stmt (r);
2511
2512 r = build_stmt (loc, RETURN_EXPR, NULL);
2513 TREE_NO_WARNING (r) |= 1; /* We don't want a warning about this. */
2514 r = maybe_cleanup_point_expr_void (r);
2515 add_stmt (r);
2516
2517 /* This is the 'continuation' return point. For such a case we have a coro
2518 handle (from the await_suspend() call) and we want handle.resume() to
2519 execute as a tailcall allowing arbitrary chaining of coroutines. */
2520 r = build_stmt (loc, LABEL_EXPR, continue_label);
2521 add_stmt (r);
2522
2523 /* We want to force a tail-call even for O0/1, so this expands the resume
2524 call into its underlying implementation. */
2525 tree addr = lookup_member (void_coro_handle_type, coro_address_identifier,
2526 1, 0, tf_warning_or_error);
2527 addr = build_new_method_call (continuation, addr, NULL, NULL_TREE,
2528 LOOKUP_NORMAL, NULL, tf_warning_or_error);
2529 tree resume = build_call_expr_loc
2530 (loc, builtin_decl_explicit (BUILT_IN_CORO_RESUME), 1, addr);
2531
2532 /* In order to support an arbitrary number of coroutine continuations,
2533 we must tail call them. However, some targets do not support indirect
2534 tail calls to arbitrary callees. See PR94359. */
2535 CALL_EXPR_TAILCALL (resume) = true;
2536 resume = coro_build_cvt_void_expr_stmt (resume, loc);
2537 add_stmt (resume);
2538
2539 r = build_stmt (loc, RETURN_EXPR, NULL);
2540 gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r);
2541 add_stmt (r);
2542
2543 /* We will need to know which resume point number should be encoded. */
2544 tree res_idx_m
2545 = lookup_member (coro_frame_type, resume_idx_name,
2546 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
2547 tree resume_pt_number
2548 = build_class_member_access_expr (actor_frame, res_idx_m, NULL_TREE, false,
2549 tf_warning_or_error);
2550
2551 /* We've now rewritten the tree and added the initial and final
2552 co_awaits. Now pass over the tree and expand the co_awaits. */
2553
2554 coro_aw_data data = {actor, actor_fp, resume_pt_number, NULL_TREE,
2555 ash, del_promise_label, ret_label,
2556 continue_label, continuation, 2};
2557 cp_walk_tree (&actor_body, await_statement_expander, &data, NULL);
2558
2559 BIND_EXPR_BODY (actor_bind) = pop_stmt_list (actor_body);
2560 TREE_SIDE_EFFECTS (actor_bind) = true;
2561
2562 finish_compound_stmt (stmt);
2563 DECL_SAVED_TREE (actor) = pop_stmt_list (actor_outer);
2564 verify_stmt_tree (DECL_SAVED_TREE (actor));
2565 }
2566
2567 /* The prototype 'destroy' function :
2568 frame->__resume_at |= 1;
2569 actor (frame); */
2570
2571 static void
build_destroy_fn(location_t loc,tree coro_frame_type,tree destroy,tree actor)2572 build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy,
2573 tree actor)
2574 {
2575 /* One param, the coro frame pointer. */
2576 tree destr_fp = DECL_ARGUMENTS (destroy);
2577
2578 /* We have a definition here. */
2579 TREE_STATIC (destroy) = 1;
2580
2581 tree destr_outer = push_stmt_list ();
2582 current_stmt_tree ()->stmts_are_full_exprs_p = 1;
2583 tree dstr_stmt = begin_compound_stmt (BCS_FN_BODY);
2584
2585 tree destr_frame = build1 (INDIRECT_REF, coro_frame_type, destr_fp);
2586
2587 tree resume_idx_name = get_identifier ("__resume_at");
2588 tree rat_field = lookup_member (coro_frame_type, resume_idx_name, 1, 0,
2589 tf_warning_or_error);
2590 tree rat = build3 (COMPONENT_REF, short_unsigned_type_node, destr_frame,
2591 rat_field, NULL_TREE);
2592
2593 /* _resume_at |= 1 */
2594 tree dstr_idx = build2 (BIT_IOR_EXPR, short_unsigned_type_node, rat,
2595 build_int_cst (short_unsigned_type_node, 1));
2596 tree r = build2 (MODIFY_EXPR, short_unsigned_type_node, rat, dstr_idx);
2597 r = coro_build_cvt_void_expr_stmt (r, loc);
2598 add_stmt (r);
2599
2600 /* So .. call the actor .. */
2601 r = build_call_expr_loc (loc, actor, 1, destr_fp);
2602 r = coro_build_cvt_void_expr_stmt (r, loc);
2603 add_stmt (r);
2604
2605 /* done. */
2606 r = build_stmt (loc, RETURN_EXPR, NULL);
2607 r = maybe_cleanup_point_expr_void (r);
2608 add_stmt (r);
2609
2610 finish_compound_stmt (dstr_stmt);
2611 DECL_SAVED_TREE (destroy) = pop_stmt_list (destr_outer);
2612 }
2613
2614 /* Helper that returns an identifier for an appended extension to the
2615 current un-mangled function name. */
2616
2617 static tree
get_fn_local_identifier(tree orig,const char * append)2618 get_fn_local_identifier (tree orig, const char *append)
2619 {
2620 /* Figure out the bits we need to generate names for the outlined things
2621 For consistency, this needs to behave the same way as
2622 ASM_FORMAT_PRIVATE_NAME does. */
2623 tree nm = DECL_NAME (orig);
2624 const char *sep, *pfx = "";
2625 #ifndef NO_DOT_IN_LABEL
2626 sep = ".";
2627 #else
2628 #ifndef NO_DOLLAR_IN_LABEL
2629 sep = "$";
2630 #else
2631 sep = "_";
2632 pfx = "__";
2633 #endif
2634 #endif
2635
2636 char *an;
2637 if (DECL_ASSEMBLER_NAME (orig))
2638 an = ACONCAT ((IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (orig)), sep, append,
2639 (char *) 0));
2640 else if (DECL_USE_TEMPLATE (orig) && DECL_TEMPLATE_INFO (orig)
2641 && DECL_TI_ARGS (orig))
2642 {
2643 tree tpl_args = DECL_TI_ARGS (orig);
2644 an = ACONCAT ((pfx, IDENTIFIER_POINTER (nm), (char *) 0));
2645 for (int i = 0; i < TREE_VEC_LENGTH (tpl_args); ++i)
2646 {
2647 tree typ = DECL_NAME (TYPE_NAME (TREE_VEC_ELT (tpl_args, i)));
2648 an = ACONCAT ((an, sep, IDENTIFIER_POINTER (typ), (char *) 0));
2649 }
2650 an = ACONCAT ((an, sep, append, (char *) 0));
2651 }
2652 else
2653 an = ACONCAT ((pfx, IDENTIFIER_POINTER (nm), sep, append, (char *) 0));
2654
2655 return get_identifier (an);
2656 }
2657
2658 /* Build an initial or final await initialized from the promise
2659 initial_suspend or final_suspend expression. */
2660
2661 static tree
build_init_or_final_await(location_t loc,bool is_final)2662 build_init_or_final_await (location_t loc, bool is_final)
2663 {
2664 tree suspend_alt = is_final ? coro_final_suspend_identifier
2665 : coro_initial_suspend_identifier;
2666
2667 tree setup_call
2668 = coro_build_promise_expression (current_function_decl, NULL, suspend_alt,
2669 loc, NULL, /*musthave=*/true);
2670
2671 /* Check for noexcept on the final_suspend call. */
2672 if (flag_exceptions && is_final && setup_call != error_mark_node
2673 && coro_diagnose_throwing_final_aw_expr (setup_call))
2674 return error_mark_node;
2675
2676 /* So build the co_await for this */
2677 /* For initial/final suspends the call is "a" per [expr.await] 3.2. */
2678 return build_co_await (loc, setup_call, (is_final ? FINAL_SUSPEND_POINT
2679 : INITIAL_SUSPEND_POINT));
2680 }
2681
2682 /* Callback to record the essential data for each await point found in the
2683 function. */
2684
2685 static bool
register_await_info(tree await_expr,tree aw_type,tree aw_nam)2686 register_await_info (tree await_expr, tree aw_type, tree aw_nam)
2687 {
2688 bool seen;
2689 suspend_point_info &s
2690 = suspend_points->get_or_insert (await_expr, &seen);
2691 if (seen)
2692 {
2693 warning_at (EXPR_LOCATION (await_expr), 0, "duplicate info for %qE",
2694 await_expr);
2695 return false;
2696 }
2697 s.awaitable_type = aw_type;
2698 s.await_field_id = aw_nam;
2699 return true;
2700 }
2701
2702 /* This data set is used when analyzing statements for await expressions. */
2703
2704 struct susp_frame_data
2705 {
2706 /* Function-wide. */
2707 tree *field_list; /* The current coroutine frame field list. */
2708 tree handle_type; /* The self-handle type for this coroutine. */
2709 tree fs_label; /* The destination for co_returns. */
2710 vec<tree, va_gc> *block_stack; /* Track block scopes. */
2711 vec<tree, va_gc> *bind_stack; /* Track current bind expr. */
2712 unsigned await_number; /* Which await in the function. */
2713 unsigned cond_number; /* Which replaced condition in the fn. */
2714 /* Temporary values for one statement or expression being analyzed. */
2715 hash_set<tree> captured_temps; /* The suspend captured these temps. */
2716 vec<tree, va_gc> *to_replace; /* The VAR decls to replace. */
2717 hash_set<tree> *truth_aoif_to_expand; /* The set of TRUTH exprs to expand. */
2718 unsigned saw_awaits; /* Count of awaits in this statement */
2719 bool captures_temporary; /* This expr captures temps by ref. */
2720 bool needs_truth_if_exp; /* We must expand a truth_if expression. */
2721 bool has_awaiter_init; /* We must handle initializing an awaiter. */
2722 };
2723
2724 /* If this is an await expression, then count it (both uniquely within the
2725 function and locally within a single statement). */
2726
2727 static tree
register_awaits(tree * stmt,int *,void * d)2728 register_awaits (tree *stmt, int *, void *d)
2729 {
2730 tree aw_expr = *stmt;
2731
2732 /* We should have already lowered co_yields to their co_await. */
2733 gcc_checking_assert (TREE_CODE (aw_expr) != CO_YIELD_EXPR);
2734
2735 if (TREE_CODE (aw_expr) != CO_AWAIT_EXPR)
2736 return NULL_TREE;
2737
2738 /* Count how many awaits the current expression contains. */
2739 susp_frame_data *data = (susp_frame_data *) d;
2740 data->saw_awaits++;
2741 /* Each await suspend context is unique, this is a function-wide value. */
2742 data->await_number++;
2743
2744 /* Awaitables should either be user-locals or promoted to coroutine frame
2745 entries at this point, and their initializers should have been broken
2746 out. */
2747 tree aw = TREE_OPERAND (aw_expr, 1);
2748 gcc_checking_assert (!TREE_OPERAND (aw_expr, 2));
2749
2750 tree aw_field_type = TREE_TYPE (aw);
2751 tree aw_field_nam = NULL_TREE;
2752 register_await_info (aw_expr, aw_field_type, aw_field_nam);
2753
2754 /* Rewrite target expressions on the await_suspend () to remove extraneous
2755 cleanups for the awaitables, which are now promoted to frame vars and
2756 managed via that. */
2757 tree v = TREE_OPERAND (aw_expr, 3);
2758 tree o = TREE_VEC_ELT (v, 1);
2759 if (TREE_CODE (o) == TARGET_EXPR)
2760 TREE_VEC_ELT (v, 1) = get_target_expr (TREE_OPERAND (o, 1));
2761 return NULL_TREE;
2762 }
2763
2764 /* There are cases where any await expression is relevant. */
2765 static tree
find_any_await(tree * stmt,int * dosub,void * d)2766 find_any_await (tree *stmt, int *dosub, void *d)
2767 {
2768 if (TREE_CODE (*stmt) == CO_AWAIT_EXPR)
2769 {
2770 *dosub = 0; /* We don't need to consider this any further. */
2771 tree **p = (tree **) d;
2772 *p = stmt;
2773 return *stmt;
2774 }
2775 return NULL_TREE;
2776 }
2777
2778 static bool
tmp_target_expr_p(tree t)2779 tmp_target_expr_p (tree t)
2780 {
2781 if (TREE_CODE (t) != TARGET_EXPR)
2782 return false;
2783 tree v = TREE_OPERAND (t, 0);
2784 if (!DECL_ARTIFICIAL (v))
2785 return false;
2786 if (DECL_NAME (v))
2787 return false;
2788 return true;
2789 }
2790
2791 /* Structure to record sub-expressions that need to be handled by the
2792 statement flattener. */
2793
2794 struct coro_interesting_subtree
2795 {
2796 tree* entry;
2797 hash_set<tree> *temps_used;
2798 };
2799
2800 /* tree-walk callback that returns the first encountered sub-expression of
2801 a kind that needs to be handled specifically by the statement flattener. */
2802
2803 static tree
find_interesting_subtree(tree * expr_p,int * dosub,void * d)2804 find_interesting_subtree (tree *expr_p, int *dosub, void *d)
2805 {
2806 tree expr = *expr_p;
2807 coro_interesting_subtree *p = (coro_interesting_subtree *)d;
2808 if (TREE_CODE (expr) == CO_AWAIT_EXPR)
2809 {
2810 *dosub = 0; /* We don't need to consider this any further. */
2811 if (TREE_OPERAND (expr, 2))
2812 {
2813 p->entry = expr_p;
2814 return expr;
2815 }
2816 }
2817 else if (tmp_target_expr_p (expr)
2818 && !p->temps_used->contains (expr))
2819 {
2820 p->entry = expr_p;
2821 return expr;
2822 }
2823
2824 return NULL_TREE;
2825 }
2826
2827 /* Node for a doubly-linked list of promoted variables and their
2828 initializers. When the initializer is a conditional expression
2829 the 'then' and 'else' clauses are represented by a linked list
2830 attached to then_cl and else_cl respectively. */
2831
2832 struct var_nest_node
2833 {
2834 var_nest_node () = default;
var_nest_nodevar_nest_node2835 var_nest_node (tree v, tree i, var_nest_node *p, var_nest_node *n)
2836 : var(v), init(i), prev(p), next(n), then_cl (NULL), else_cl (NULL)
2837 {
2838 if (p)
2839 p->next = this;
2840 if (n)
2841 n->prev = this;
2842 }
2843 tree var;
2844 tree init;
2845 var_nest_node *prev;
2846 var_nest_node *next;
2847 var_nest_node *then_cl;
2848 var_nest_node *else_cl;
2849 };
2850
2851 /* This is called for single statements from the co-await statement walker.
2852 It checks to see if the statement contains any initializers for awaitables
2853 and if any of these capture items by reference. */
2854
2855 static void
flatten_await_stmt(var_nest_node * n,hash_set<tree> * promoted,hash_set<tree> * temps_used,tree * replace_in)2856 flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
2857 hash_set<tree> *temps_used, tree *replace_in)
2858 {
2859 bool init_expr = false;
2860 switch (TREE_CODE (n->init))
2861 {
2862 default: break;
2863 /* Compound expressions must be flattened specifically. */
2864 case COMPOUND_EXPR:
2865 {
2866 tree first = TREE_OPERAND (n->init, 0);
2867 n->init = TREE_OPERAND (n->init, 1);
2868 var_nest_node *ins
2869 = new var_nest_node(NULL_TREE, first, n->prev, n);
2870 /* The compiler (but not the user) can generate temporaries with
2871 uses in the second arm of a compound expr. */
2872 flatten_await_stmt (ins, promoted, temps_used, &n->init);
2873 flatten_await_stmt (n, promoted, temps_used, NULL);
2874 /* The two arms have been processed separately. */
2875 return;
2876 }
2877 break;
2878 /* Handle conditional expressions. */
2879 case INIT_EXPR:
2880 init_expr = true;
2881 /* FALLTHROUGH */
2882 case MODIFY_EXPR:
2883 {
2884 tree old_expr = TREE_OPERAND (n->init, 1);
2885 if (TREE_CODE (old_expr) == COMPOUND_EXPR)
2886 {
2887 tree first = TREE_OPERAND (old_expr, 0);
2888 TREE_OPERAND (n->init, 1) = TREE_OPERAND (old_expr, 1);
2889 var_nest_node *ins
2890 = new var_nest_node(NULL_TREE, first, n->prev, n);
2891 flatten_await_stmt (ins, promoted, temps_used,
2892 &TREE_OPERAND (n->init, 1));
2893 flatten_await_stmt (n, promoted, temps_used, NULL);
2894 return;
2895 }
2896 if (TREE_CODE (old_expr) != COND_EXPR)
2897 break;
2898 /* Reconstruct x = t ? y : z;
2899 as (void) t ? x = y : x = z; */
2900 tree var = TREE_OPERAND (n->init, 0);
2901 tree var_type = TREE_TYPE (var);
2902 tree cond = COND_EXPR_COND (old_expr);
2903 /* We are allowed a void type throw in one or both of the cond
2904 expr arms. */
2905 tree then_cl = COND_EXPR_THEN (old_expr);
2906 if (!VOID_TYPE_P (TREE_TYPE (then_cl)))
2907 {
2908 gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST);
2909 then_cl
2910 = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
2911 var, then_cl);
2912 }
2913 tree else_cl = COND_EXPR_ELSE (old_expr);
2914 if (!VOID_TYPE_P (TREE_TYPE (else_cl)))
2915 {
2916 gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST);
2917 else_cl
2918 = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
2919 var, else_cl);
2920 }
2921 n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl);
2922 }
2923 /* FALLTHROUGH */
2924 case COND_EXPR:
2925 {
2926 tree *found;
2927 tree cond = COND_EXPR_COND (n->init);
2928 /* If the condition contains an await expression, then we need to
2929 set that first and use a separate var. */
2930 if (cp_walk_tree (&cond, find_any_await, &found, NULL))
2931 {
2932 tree cond_type = TREE_TYPE (cond);
2933 tree cond_var = build_lang_decl (VAR_DECL, NULL_TREE, cond_type);
2934 DECL_ARTIFICIAL (cond_var) = true;
2935 layout_decl (cond_var, 0);
2936 gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type));
2937 cond = build2 (INIT_EXPR, cond_type, cond_var, cond);
2938 var_nest_node *ins
2939 = new var_nest_node (cond_var, cond, n->prev, n);
2940 COND_EXPR_COND (n->init) = cond_var;
2941 flatten_await_stmt (ins, promoted, temps_used, NULL);
2942 }
2943
2944 n->then_cl
2945 = new var_nest_node (n->var, COND_EXPR_THEN (n->init), NULL, NULL);
2946 n->else_cl
2947 = new var_nest_node (n->var, COND_EXPR_ELSE (n->init), NULL, NULL);
2948 flatten_await_stmt (n->then_cl, promoted, temps_used, NULL);
2949 /* Point to the start of the flattened code. */
2950 while (n->then_cl->prev)
2951 n->then_cl = n->then_cl->prev;
2952 flatten_await_stmt (n->else_cl, promoted, temps_used, NULL);
2953 while (n->else_cl->prev)
2954 n->else_cl = n->else_cl->prev;
2955 return;
2956 }
2957 break;
2958 }
2959 coro_interesting_subtree v = { NULL, temps_used };
2960 tree t = cp_walk_tree (&n->init, find_interesting_subtree, (void *)&v, NULL);
2961 if (!t)
2962 return;
2963 switch (TREE_CODE (t))
2964 {
2965 default: break;
2966 case CO_AWAIT_EXPR:
2967 {
2968 /* Await expressions with initializers have a compiler-temporary
2969 as the awaitable. 'promote' this. */
2970 tree var = TREE_OPERAND (t, 1);
2971 bool already_present = promoted->add (var);
2972 gcc_checking_assert (!already_present);
2973 tree init = TREE_OPERAND (t, 2);
2974 switch (TREE_CODE (init))
2975 {
2976 default: break;
2977 case INIT_EXPR:
2978 case MODIFY_EXPR:
2979 {
2980 tree inner = TREE_OPERAND (init, 1);
2981 /* We can have non-lvalue-expressions here, but when we see
2982 a target expression, mark it as already used. */
2983 if (TREE_CODE (inner) == TARGET_EXPR)
2984 {
2985 temps_used->add (inner);
2986 gcc_checking_assert
2987 (TREE_CODE (TREE_OPERAND (inner, 1)) != COND_EXPR);
2988 }
2989 }
2990 break;
2991 case CALL_EXPR:
2992 /* If this is a call and not a CTOR, then we didn't expect it. */
2993 gcc_checking_assert
2994 (DECL_CONSTRUCTOR_P (TREE_OPERAND (CALL_EXPR_FN (init), 0)));
2995 break;
2996 }
2997 var_nest_node *ins = new var_nest_node (var, init, n->prev, n);
2998 TREE_OPERAND (t, 2) = NULL_TREE;
2999 flatten_await_stmt (ins, promoted, temps_used, NULL);
3000 flatten_await_stmt (n, promoted, temps_used, NULL);
3001 return;
3002 }
3003 break;
3004 case TARGET_EXPR:
3005 {
3006 /* We have a temporary; promote it, but allow for the idiom in code
3007 generated by the compiler like
3008 a = (target_expr produces temp, op uses temp). */
3009 tree init = t;
3010 temps_used->add (init);
3011 tree var_type = TREE_TYPE (init);
3012 char *buf = xasprintf ("D.%d", DECL_UID (TREE_OPERAND (init, 0)));
3013 tree var = build_lang_decl (VAR_DECL, get_identifier (buf), var_type);
3014 DECL_ARTIFICIAL (var) = true;
3015 free (buf);
3016 bool already_present = promoted->add (var);
3017 gcc_checking_assert (!already_present);
3018 tree inner = TREE_OPERAND (init, 1);
3019 gcc_checking_assert (TREE_CODE (inner) != COND_EXPR);
3020 if (type_build_ctor_call (var_type))
3021 {
3022 releasing_vec p_in (make_tree_vector_single (init));
3023 init = build_special_member_call (var, complete_ctor_identifier,
3024 &p_in, var_type, LOOKUP_NORMAL,
3025 tf_warning_or_error);
3026 }
3027 else
3028 init = build2 (INIT_EXPR, var_type, var, init);
3029 /* Simplify for the case that we have an init containing the temp
3030 alone. */
3031 if (t == n->init && n->var == NULL_TREE)
3032 {
3033 n->var = var;
3034 proxy_replace pr = {TREE_OPERAND (t, 0), var};
3035 cp_walk_tree (&init, replace_proxy, &pr, NULL);
3036 n->init = init;
3037 if (replace_in)
3038 cp_walk_tree (replace_in, replace_proxy, &pr, NULL);
3039 flatten_await_stmt (n, promoted, temps_used, NULL);
3040 }
3041 else
3042 {
3043 var_nest_node *ins
3044 = new var_nest_node (var, init, n->prev, n);
3045 /* We have to replace the target expr... */
3046 *v.entry = var;
3047 /* ... and any uses of its var. */
3048 proxy_replace pr = {TREE_OPERAND (t, 0), var};
3049 cp_walk_tree (&n->init, replace_proxy, &pr, NULL);
3050 /* Compiler-generated temporaries can also have uses in
3051 following arms of compound expressions, which will be listed
3052 in 'replace_in' if present. */
3053 if (replace_in)
3054 cp_walk_tree (replace_in, replace_proxy, &pr, NULL);
3055 flatten_await_stmt (ins, promoted, temps_used, NULL);
3056 flatten_await_stmt (n, promoted, temps_used, NULL);
3057 }
3058 return;
3059 }
3060 break;
3061 }
3062 }
3063
3064 /* Helper for 'process_conditional' that handles recursion into nested
3065 conditionals. */
3066
3067 static void
handle_nested_conditionals(var_nest_node * n,vec<tree> & list,hash_map<tree,tree> & map)3068 handle_nested_conditionals (var_nest_node *n, vec<tree>& list,
3069 hash_map<tree, tree>& map)
3070 {
3071 do
3072 {
3073 if (n->var && DECL_NAME (n->var))
3074 {
3075 list.safe_push (n->var);
3076 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (n->var)))
3077 {
3078 bool existed;
3079 tree& flag = map.get_or_insert (n->var, &existed);
3080 if (!existed)
3081 {
3082 /* We didn't see this var before and it needs a DTOR, so
3083 build a guard variable for it. */
3084 char *nam
3085 = xasprintf ("%s_guard",
3086 IDENTIFIER_POINTER (DECL_NAME (n->var)));
3087 flag = build_lang_decl (VAR_DECL, get_identifier (nam),
3088 boolean_type_node);
3089 free (nam);
3090 DECL_ARTIFICIAL (flag) = true;
3091 }
3092
3093 /* The initializer for this variable is replaced by a compound
3094 expression that performs the init and then records that the
3095 variable is live (and the DTOR should be run at the scope
3096 exit. */
3097 tree set_flag = build2 (INIT_EXPR, boolean_type_node,
3098 flag, boolean_true_node);
3099 n->init
3100 = build2 (COMPOUND_EXPR, boolean_type_node, n->init, set_flag);
3101 }
3102 }
3103 if (TREE_CODE (n->init) == COND_EXPR)
3104 {
3105 tree new_then = push_stmt_list ();
3106 handle_nested_conditionals (n->then_cl, list, map);
3107 new_then = pop_stmt_list (new_then);
3108 tree new_else = push_stmt_list ();
3109 handle_nested_conditionals (n->else_cl, list, map);
3110 new_else = pop_stmt_list (new_else);
3111 tree new_if
3112 = build4 (IF_STMT, void_type_node, COND_EXPR_COND (n->init),
3113 new_then, new_else, NULL_TREE);
3114 add_stmt (new_if);
3115 }
3116 else
3117 finish_expr_stmt (n->init);
3118 n = n->next;
3119 } while (n);
3120 }
3121
3122 /* helper for 'maybe_promote_temps'.
3123
3124 When we have a conditional expression which might embed await expressions
3125 and/or promoted variables, we need to handle it appropriately.
3126
3127 The linked lists for the 'then' and 'else' clauses in a conditional node
3128 identify the promoted variables (but these cannot be wrapped in a regular
3129 cleanup).
3130
3131 So recurse through the lists and build up a composite list of captured vars.
3132 Declare these and any guard variables needed to decide if a DTOR should be
3133 run. Then embed the conditional into a try-finally expression that handles
3134 running each DTOR conditionally on its guard variable. */
3135
3136 static void
process_conditional(var_nest_node * n,tree & vlist)3137 process_conditional (var_nest_node *n, tree& vlist)
3138 {
3139 tree init = n->init;
3140 hash_map<tree, tree> var_flags;
3141 vec<tree> var_list = vNULL;
3142 tree new_then = push_stmt_list ();
3143 handle_nested_conditionals (n->then_cl, var_list, var_flags);
3144 new_then = pop_stmt_list (new_then);
3145 tree new_else = push_stmt_list ();
3146 handle_nested_conditionals (n->else_cl, var_list, var_flags);
3147 new_else = pop_stmt_list (new_else);
3148 /* Declare the vars. There are two loops so that the boolean flags are
3149 grouped in the frame. */
3150 for (unsigned i = 0; i < var_list.length(); i++)
3151 {
3152 tree var = var_list[i];
3153 DECL_CHAIN (var) = vlist;
3154 vlist = var;
3155 add_decl_expr (var);
3156 }
3157 /* Define the guard flags for variables that need a DTOR. */
3158 for (unsigned i = 0; i < var_list.length(); i++)
3159 {
3160 tree *flag = var_flags.get (var_list[i]);
3161 if (flag)
3162 {
3163 DECL_INITIAL (*flag) = boolean_false_node;
3164 DECL_CHAIN (*flag) = vlist;
3165 vlist = *flag;
3166 add_decl_expr (*flag);
3167 }
3168 }
3169 tree new_if
3170 = build4 (IF_STMT, void_type_node, COND_EXPR_COND (init),
3171 new_then, new_else, NULL_TREE);
3172 /* Build a set of conditional DTORs. */
3173 tree final_actions = push_stmt_list ();
3174 while (!var_list.is_empty())
3175 {
3176 tree var = var_list.pop ();
3177 tree *flag = var_flags.get (var);
3178 if (!flag)
3179 continue;
3180 tree var_type = TREE_TYPE (var);
3181 tree cleanup
3182 = build_special_member_call (var, complete_dtor_identifier,
3183 NULL, var_type, LOOKUP_NORMAL,
3184 tf_warning_or_error);
3185 tree cond_cleanup = begin_if_stmt ();
3186 finish_if_stmt_cond (*flag, cond_cleanup);
3187 finish_expr_stmt (cleanup);
3188 finish_then_clause (cond_cleanup);
3189 finish_if_stmt (cond_cleanup);
3190 }
3191 final_actions = pop_stmt_list (final_actions);
3192 tree try_finally
3193 = build2 (TRY_FINALLY_EXPR, void_type_node, new_if, final_actions);
3194 add_stmt (try_finally);
3195 }
3196
3197 /* Given *STMT, that contains at least one await expression.
3198
3199 The full expression represented in the original source code will contain
3200 suspension points, but it is still required that the lifetime of temporary
3201 values extends to the end of the expression.
3202
3203 We already have a mechanism to 'promote' user-authored local variables
3204 to a coroutine frame counterpart (which allows explicit management of the
3205 lifetime across suspensions). The transform here re-writes STMT into
3206 a bind expression, promotes temporary values into local variables in that
3207 and flattens the statement into a series of cleanups.
3208
3209 Conditional expressions are re-written to regular 'if' statements.
3210 The cleanups for variables initialized inside a conditional (including
3211 nested cases) are wrapped in a try-finally clause, with guard variables
3212 to determine which DTORs need to be run. */
3213
3214 static tree
maybe_promote_temps(tree * stmt,void * d)3215 maybe_promote_temps (tree *stmt, void *d)
3216 {
3217 susp_frame_data *awpts = (susp_frame_data *) d;
3218
3219 location_t sloc = EXPR_LOCATION (*stmt);
3220 tree expr = *stmt;
3221 /* Strip off uninteresting wrappers. */
3222 if (TREE_CODE (expr) == CLEANUP_POINT_EXPR)
3223 expr = TREE_OPERAND (expr, 0);
3224 if (TREE_CODE (expr) == EXPR_STMT)
3225 expr = EXPR_STMT_EXPR (expr);
3226 if (TREE_CODE (expr) == CONVERT_EXPR
3227 && VOID_TYPE_P (TREE_TYPE (expr)))
3228 expr = TREE_OPERAND (expr, 0);
3229 STRIP_NOPS (expr);
3230
3231 /* We walk the statement trees, flattening it into an ordered list of
3232 variables with initializers and fragments corresponding to compound
3233 expressions, truth or/and if and ternary conditionals. Conditional
3234 expressions carry a nested list of fragments for the then and else
3235 clauses. We anchor to the 'bottom' of the fragment list; we will write
3236 a cleanup nest with one shell for each variable initialized. */
3237 var_nest_node *root = new var_nest_node (NULL_TREE, expr, NULL, NULL);
3238 /* Check to see we didn't promote one twice. */
3239 hash_set<tree> promoted_vars;
3240 hash_set<tree> used_temps;
3241 flatten_await_stmt (root, &promoted_vars, &used_temps, NULL);
3242
3243 gcc_checking_assert (root->next == NULL);
3244 tree vlist = NULL_TREE;
3245 var_nest_node *t = root;
3246 /* We build the bind scope expression from the bottom-up.
3247 EXPR_LIST holds the inner expression nest at the current cleanup
3248 level (becoming the final expression list when we've exhausted the
3249 number of sub-expression fragments). */
3250 tree expr_list = NULL_TREE;
3251 do
3252 {
3253 tree new_list = push_stmt_list ();
3254 /* When we have a promoted variable, then add that to the bind scope
3255 and initialize it. When there's no promoted variable, we just need
3256 to run the initializer.
3257 If the initializer is a conditional expression, we need to collect
3258 and declare any promoted variables nested within it. DTORs for such
3259 variables must be run conditionally too. */
3260 if (t->var && DECL_NAME (t->var))
3261 {
3262 tree var = t->var;
3263 DECL_CHAIN (var) = vlist;
3264 vlist = var;
3265 add_decl_expr (var);
3266 if (TREE_CODE (t->init) == COND_EXPR)
3267 process_conditional (t, vlist);
3268 else
3269 finish_expr_stmt (t->init);
3270 tree var_type = TREE_TYPE (var);
3271 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (var_type))
3272 {
3273 tree cleanup
3274 = build_special_member_call (var, complete_dtor_identifier,
3275 NULL, var_type, LOOKUP_NORMAL,
3276 tf_warning_or_error);
3277 tree cl = build_stmt (sloc, CLEANUP_STMT, expr_list, cleanup, var);
3278 add_stmt (cl); /* push this onto the level above. */
3279 }
3280 else if (expr_list)
3281 {
3282 if (TREE_CODE (expr_list) != STATEMENT_LIST)
3283 add_stmt (expr_list);
3284 else if (!tsi_end_p (tsi_start (expr_list)))
3285 add_stmt (expr_list);
3286 }
3287 }
3288 else
3289 {
3290 if (TREE_CODE (t->init) == COND_EXPR)
3291 process_conditional (t, vlist);
3292 else
3293 finish_expr_stmt (t->init);
3294 if (expr_list)
3295 {
3296 if (TREE_CODE (expr_list) != STATEMENT_LIST)
3297 add_stmt (expr_list);
3298 else if (!tsi_end_p (tsi_start (expr_list)))
3299 add_stmt (expr_list);
3300 }
3301 }
3302 expr_list = pop_stmt_list (new_list);
3303 var_nest_node *old = t;
3304 t = t->prev;
3305 delete old;
3306 } while (t);
3307
3308 /* Now produce the bind expression containing the 'promoted' temporaries
3309 as its variable list, and the cleanup nest as the statement. */
3310 tree await_bind = build3_loc (sloc, BIND_EXPR, void_type_node,
3311 NULL, NULL, NULL);
3312 BIND_EXPR_BODY (await_bind) = expr_list;
3313 BIND_EXPR_VARS (await_bind) = nreverse (vlist);
3314 tree b_block = make_node (BLOCK);
3315 if (!awpts->block_stack->is_empty ())
3316 {
3317 tree s_block = awpts->block_stack->last ();
3318 if (s_block)
3319 {
3320 BLOCK_SUPERCONTEXT (b_block) = s_block;
3321 BLOCK_CHAIN (b_block) = BLOCK_SUBBLOCKS (s_block);
3322 BLOCK_SUBBLOCKS (s_block) = b_block;
3323 }
3324 }
3325 BLOCK_VARS (b_block) = BIND_EXPR_VARS (await_bind) ;
3326 BIND_EXPR_BLOCK (await_bind) = b_block;
3327 TREE_SIDE_EFFECTS (await_bind) = TREE_SIDE_EFFECTS (BIND_EXPR_BODY (await_bind));
3328 *stmt = await_bind;
3329 hash_set<tree> visited;
3330 return cp_walk_tree (stmt, register_awaits, d, &visited);
3331 }
3332
3333 /* Lightweight callback to determine two key factors:
3334 1) If the statement/expression contains any await expressions.
3335 2) If the statement/expression potentially requires a re-write to handle
3336 TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion
3337 so that the await expressions are not processed in the case of the
3338 short-circuit arm.
3339
3340 CO_YIELD expressions are re-written to their underlying co_await. */
3341
3342 static tree
analyze_expression_awaits(tree * stmt,int * do_subtree,void * d)3343 analyze_expression_awaits (tree *stmt, int *do_subtree, void *d)
3344 {
3345 susp_frame_data *awpts = (susp_frame_data *) d;
3346
3347 switch (TREE_CODE (*stmt))
3348 {
3349 default: return NULL_TREE;
3350 case CO_YIELD_EXPR:
3351 /* co_yield is syntactic sugar, re-write it to co_await. */
3352 *stmt = TREE_OPERAND (*stmt, 1);
3353 /* FALLTHROUGH */
3354 case CO_AWAIT_EXPR:
3355 awpts->saw_awaits++;
3356 /* A non-null initializer for the awaiter means we need to expand. */
3357 if (TREE_OPERAND (*stmt, 2))
3358 awpts->has_awaiter_init = true;
3359 break;
3360 case TRUTH_ANDIF_EXPR:
3361 case TRUTH_ORIF_EXPR:
3362 {
3363 /* We don't need special action for awaits in the always-executed
3364 arm of a TRUTH_IF. */
3365 if (tree res = cp_walk_tree (&TREE_OPERAND (*stmt, 0),
3366 analyze_expression_awaits, d, NULL))
3367 return res;
3368 /* However, if there are await expressions on the conditionally
3369 executed branch, we must expand the TRUTH_IF to ensure that the
3370 expanded await expression control-flow is fully contained in the
3371 conditionally executed code. */
3372 unsigned aw_count = awpts->saw_awaits;
3373 if (tree res = cp_walk_tree (&TREE_OPERAND (*stmt, 1),
3374 analyze_expression_awaits, d, NULL))
3375 return res;
3376 if (awpts->saw_awaits > aw_count)
3377 {
3378 awpts->truth_aoif_to_expand->add (*stmt);
3379 awpts->needs_truth_if_exp = true;
3380 }
3381 /* We've done the sub-trees here. */
3382 *do_subtree = 0;
3383 }
3384 break;
3385 }
3386
3387 return NULL_TREE; /* Recurse until done. */
3388 }
3389
3390 /* Given *EXPR
3391 If EXPR contains a TRUTH_{AND,OR}IF_EXPR, TAOIE with an await expr on
3392 the conditionally executed branch, change this in a ternary operator.
3393
3394 bool not_expr = TAOIE == TRUTH_ORIF_EXPR ? NOT : NOP;
3395 not_expr (always-exec expr) ? conditionally-exec expr : not_expr;
3396
3397 Apply this recursively to the condition and the conditionally-exec
3398 branch. */
3399
3400 struct truth_if_transform {
3401 tree *orig_stmt;
3402 tree scratch_var;
3403 hash_set<tree> *truth_aoif_to_expand;
3404 };
3405
3406 static tree
expand_one_truth_if(tree * expr,int * do_subtree,void * d)3407 expand_one_truth_if (tree *expr, int *do_subtree, void *d)
3408 {
3409 truth_if_transform *xform = (truth_if_transform *) d;
3410
3411 bool needs_not = false;
3412 switch (TREE_CODE (*expr))
3413 {
3414 default: break;
3415 case TRUTH_ORIF_EXPR:
3416 needs_not = true;
3417 /* FALLTHROUGH */
3418 case TRUTH_ANDIF_EXPR:
3419 {
3420 if (!xform->truth_aoif_to_expand->contains (*expr))
3421 break;
3422
3423 location_t sloc = EXPR_LOCATION (*expr);
3424 /* Transform truth expression into a cond expression with
3425 * the always-executed arm as the condition.
3426 * the conditionally-executed arm as the then clause.
3427 * the 'else' clause is fixed: 'true' for ||,'false' for &&. */
3428 tree cond = TREE_OPERAND (*expr, 0);
3429 tree test1 = TREE_OPERAND (*expr, 1);
3430 tree fixed = needs_not ? boolean_true_node : boolean_false_node;
3431 if (needs_not)
3432 cond = build1 (TRUTH_NOT_EXPR, boolean_type_node, cond);
3433 tree cond_expr
3434 = build3_loc (sloc, COND_EXPR, boolean_type_node,
3435 cond, test1, fixed);
3436 *expr = cond_expr;
3437 if (tree res = cp_walk_tree (&COND_EXPR_COND (*expr),
3438 expand_one_truth_if, d, NULL))
3439 return res;
3440 if (tree res = cp_walk_tree (&COND_EXPR_THEN (*expr),
3441 expand_one_truth_if, d, NULL))
3442 return res;
3443 /* We've manually processed necessary sub-trees here. */
3444 *do_subtree = 0;
3445 }
3446 break;
3447 }
3448 return NULL_TREE;
3449 }
3450
3451 /* Helper that adds a new variable of VAR_TYPE to a bind scope BIND, the
3452 name is made up from NAM_ROOT, NAM_VERS. */
3453
3454 static tree
add_var_to_bind(tree & bind,tree var_type,const char * nam_root,unsigned nam_vers)3455 add_var_to_bind (tree& bind, tree var_type,
3456 const char *nam_root, unsigned nam_vers)
3457 {
3458 tree b_vars = BIND_EXPR_VARS (bind);
3459 /* Build a variable to hold the condition, this will be included in the
3460 frame as a local var. */
3461 char *nam = xasprintf ("%s.%d", nam_root, nam_vers);
3462 tree newvar = build_lang_decl (VAR_DECL, get_identifier (nam), var_type);
3463 free (nam);
3464 DECL_CHAIN (newvar) = b_vars;
3465 BIND_EXPR_VARS (bind) = newvar;
3466 return newvar;
3467 }
3468
3469 /* Helper to build and add if (!cond) break; */
3470
3471 static void
coro_build_add_if_not_cond_break(tree cond)3472 coro_build_add_if_not_cond_break (tree cond)
3473 {
3474 tree if_stmt = begin_if_stmt ();
3475 tree invert = build1 (TRUTH_NOT_EXPR, boolean_type_node, cond);
3476 finish_if_stmt_cond (invert, if_stmt);
3477 finish_break_stmt ();
3478 finish_then_clause (if_stmt);
3479 finish_if_stmt (if_stmt);
3480 }
3481
3482 /* Tree walk callback to replace continue statements with goto label. */
3483 static tree
replace_continue(tree * stmt,int * do_subtree,void * d)3484 replace_continue (tree *stmt, int *do_subtree, void *d)
3485 {
3486 tree expr = *stmt;
3487 if (TREE_CODE (expr) == CLEANUP_POINT_EXPR)
3488 expr = TREE_OPERAND (expr, 0);
3489 if (CONVERT_EXPR_P (expr) && VOID_TYPE_P (expr))
3490 expr = TREE_OPERAND (expr, 0);
3491 STRIP_NOPS (expr);
3492 if (!STATEMENT_CLASS_P (expr))
3493 return NULL_TREE;
3494
3495 switch (TREE_CODE (expr))
3496 {
3497 /* Unless it's a special case, just walk the subtrees as usual. */
3498 default: return NULL_TREE;
3499
3500 case CONTINUE_STMT:
3501 {
3502 tree *label = (tree *)d;
3503 location_t loc = EXPR_LOCATION (expr);
3504 /* re-write a continue to goto label. */
3505 *stmt = build_stmt (loc, GOTO_EXPR, *label);
3506 *do_subtree = 0;
3507 return NULL_TREE;
3508 }
3509
3510 /* Statements that do not require recursion. */
3511 case DECL_EXPR:
3512 case BREAK_STMT:
3513 case GOTO_EXPR:
3514 case LABEL_EXPR:
3515 case CASE_LABEL_EXPR:
3516 case ASM_EXPR:
3517 /* These must break recursion. */
3518 case FOR_STMT:
3519 case WHILE_STMT:
3520 case DO_STMT:
3521 *do_subtree = 0;
3522 return NULL_TREE;
3523 }
3524 }
3525
3526 /* Tree walk callback to analyze, register and pre-process statements that
3527 contain await expressions. */
3528
3529 static tree
await_statement_walker(tree * stmt,int * do_subtree,void * d)3530 await_statement_walker (tree *stmt, int *do_subtree, void *d)
3531 {
3532 tree res = NULL_TREE;
3533 susp_frame_data *awpts = (susp_frame_data *) d;
3534
3535 /* Process a statement at a time. */
3536 if (TREE_CODE (*stmt) == BIND_EXPR)
3537 {
3538 /* For conditional expressions, we might wish to add an artificial var
3539 to their containing bind expr. */
3540 vec_safe_push (awpts->bind_stack, *stmt);
3541 /* We might need to insert a new bind expression, and want to link it
3542 into the correct scope, so keep a note of the current block scope. */
3543 tree blk = BIND_EXPR_BLOCK (*stmt);
3544 vec_safe_push (awpts->block_stack, blk);
3545 res = cp_walk_tree (&BIND_EXPR_BODY (*stmt), await_statement_walker,
3546 d, NULL);
3547 awpts->block_stack->pop ();
3548 awpts->bind_stack->pop ();
3549 *do_subtree = 0; /* Done subtrees. */
3550 return res;
3551 }
3552 else if (TREE_CODE (*stmt) == STATEMENT_LIST)
3553 {
3554 tree_stmt_iterator i;
3555 for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i))
3556 {
3557 res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_walker,
3558 d, NULL);
3559 if (res)
3560 return res;
3561 }
3562 *do_subtree = 0; /* Done subtrees. */
3563 return NULL_TREE;
3564 }
3565
3566 /* We have something to be handled as a single statement. */
3567 bool has_cleanup_wrapper = TREE_CODE (*stmt) == CLEANUP_POINT_EXPR;
3568 hash_set<tree> visited;
3569 awpts->saw_awaits = 0;
3570 hash_set<tree> truth_aoif_to_expand;
3571 awpts->truth_aoif_to_expand = &truth_aoif_to_expand;
3572 awpts->needs_truth_if_exp = false;
3573 awpts->has_awaiter_init = false;
3574 tree expr = *stmt;
3575 if (has_cleanup_wrapper)
3576 expr = TREE_OPERAND (expr, 0);
3577 STRIP_NOPS (expr);
3578
3579 if (STATEMENT_CLASS_P (expr))
3580 switch (TREE_CODE (expr))
3581 {
3582 /* Unless it's a special case, just walk the subtrees as usual. */
3583 default: return NULL_TREE;
3584
3585 /* When we have a conditional expression, which contains one or more
3586 await expressions, we have to break the condition out into a
3587 regular statement so that the control flow introduced by the await
3588 transforms can be implemented. */
3589 case IF_STMT:
3590 {
3591 /* Transform 'if (cond with awaits) then stmt1 else stmt2' into
3592 bool cond = cond with awaits.
3593 if (cond) then stmt1 else stmt2. */
3594 tree if_stmt = *stmt;
3595 /* We treat the condition as if it was a stand-alone statement,
3596 to see if there are any await expressions which will be analyzed
3597 and registered. */
3598 if ((res = cp_walk_tree (&IF_COND (if_stmt),
3599 analyze_expression_awaits, d, &visited)))
3600 return res;
3601 if (!awpts->saw_awaits)
3602 return NULL_TREE; /* Nothing special to do here. */
3603
3604 gcc_checking_assert (!awpts->bind_stack->is_empty());
3605 tree& bind_expr = awpts->bind_stack->last ();
3606 tree newvar = add_var_to_bind (bind_expr, boolean_type_node,
3607 "ifcd", awpts->cond_number++);
3608 tree insert_list = push_stmt_list ();
3609 tree cond_inner = IF_COND (if_stmt);
3610 if (TREE_CODE (cond_inner) == CLEANUP_POINT_EXPR)
3611 cond_inner = TREE_OPERAND (cond_inner, 0);
3612 add_decl_expr (newvar);
3613 location_t sloc = EXPR_LOCATION (IF_COND (if_stmt));
3614 /* We want to initialize the new variable with the expression
3615 that contains the await(s) and potentially also needs to
3616 have truth_if expressions expanded. */
3617 tree new_s = build2_loc (sloc, MODIFY_EXPR, boolean_type_node,
3618 newvar, cond_inner);
3619 finish_expr_stmt (new_s);
3620 IF_COND (if_stmt) = newvar;
3621 add_stmt (if_stmt);
3622 *stmt = pop_stmt_list (insert_list);
3623 /* So now walk the new statement list. */
3624 res = cp_walk_tree (stmt, await_statement_walker, d, NULL);
3625 *do_subtree = 0; /* Done subtrees. */
3626 return res;
3627 }
3628 break;
3629 case FOR_STMT:
3630 {
3631 /* for loops only need special treatment if the condition or the
3632 iteration expression contain a co_await. */
3633 tree for_stmt = *stmt;
3634 /* Sanity check. */
3635 if ((res = cp_walk_tree (&FOR_INIT_STMT (for_stmt),
3636 analyze_expression_awaits, d, &visited)))
3637 return res;
3638 gcc_checking_assert (!awpts->saw_awaits);
3639
3640 if ((res = cp_walk_tree (&FOR_COND (for_stmt),
3641 analyze_expression_awaits, d, &visited)))
3642 return res;
3643 bool for_cond_await = awpts->saw_awaits != 0;
3644 unsigned save_awaits = awpts->saw_awaits;
3645
3646 if ((res = cp_walk_tree (&FOR_EXPR (for_stmt),
3647 analyze_expression_awaits, d, &visited)))
3648 return res;
3649 bool for_expr_await = awpts->saw_awaits > save_awaits;
3650
3651 /* If the condition has an await, then we will need to rewrite the
3652 loop as
3653 for (init expression;true;iteration expression) {
3654 condition = await expression;
3655 if (condition)
3656 break;
3657 ...
3658 }
3659 */
3660 if (for_cond_await)
3661 {
3662 tree insert_list = push_stmt_list ();
3663 /* This will be expanded when the revised body is handled. */
3664 coro_build_add_if_not_cond_break (FOR_COND (for_stmt));
3665 /* .. add the original for body. */
3666 add_stmt (FOR_BODY (for_stmt));
3667 /* To make the new for body. */
3668 FOR_BODY (for_stmt) = pop_stmt_list (insert_list);
3669 FOR_COND (for_stmt) = boolean_true_node;
3670 }
3671 /* If the iteration expression has an await, it's a bit more
3672 tricky.
3673 for (init expression;condition;) {
3674 ...
3675 iteration_expr_label:
3676 iteration expression with await;
3677 }
3678 but, then we will need to re-write any continue statements into
3679 'goto iteration_expr_label:'.
3680 */
3681 if (for_expr_await)
3682 {
3683 location_t sloc = EXPR_LOCATION (FOR_EXPR (for_stmt));
3684 tree insert_list = push_stmt_list ();
3685 /* The original for body. */
3686 add_stmt (FOR_BODY (for_stmt));
3687 char *buf = xasprintf ("for.iter.expr.%u", awpts->cond_number++);
3688 tree it_expr_label
3689 = create_named_label_with_ctx (sloc, buf, NULL_TREE);
3690 free (buf);
3691 add_stmt (build_stmt (sloc, LABEL_EXPR, it_expr_label));
3692 add_stmt (FOR_EXPR (for_stmt));
3693 FOR_EXPR (for_stmt) = NULL_TREE;
3694 FOR_BODY (for_stmt) = pop_stmt_list (insert_list);
3695 /* rewrite continue statements to goto label. */
3696 hash_set<tree> visited_continue;
3697 if ((res = cp_walk_tree (&FOR_BODY (for_stmt),
3698 replace_continue, &it_expr_label, &visited_continue)))
3699 return res;
3700 }
3701
3702 /* So now walk the body statement (list), if there were no await
3703 expressions, then this handles the original body - and either
3704 way we will have finished with this statement. */
3705 res = cp_walk_tree (&FOR_BODY (for_stmt),
3706 await_statement_walker, d, NULL);
3707 *do_subtree = 0; /* Done subtrees. */
3708 return res;
3709 }
3710 break;
3711 case WHILE_STMT:
3712 {
3713 /* We turn 'while (cond with awaits) stmt' into
3714 while (true) {
3715 if (!(cond with awaits))
3716 break;
3717 stmt..
3718 } */
3719 tree while_stmt = *stmt;
3720 if ((res = cp_walk_tree (&WHILE_COND (while_stmt),
3721 analyze_expression_awaits, d, &visited)))
3722 return res;
3723 if (!awpts->saw_awaits)
3724 return NULL_TREE; /* Nothing special to do here. */
3725
3726 tree insert_list = push_stmt_list ();
3727 coro_build_add_if_not_cond_break (WHILE_COND (while_stmt));
3728 /* The original while body. */
3729 add_stmt (WHILE_BODY (while_stmt));
3730 /* The new while body. */
3731 WHILE_BODY (while_stmt) = pop_stmt_list (insert_list);
3732 WHILE_COND (while_stmt) = boolean_true_node;
3733 /* So now walk the new statement list. */
3734 res = cp_walk_tree (&WHILE_BODY (while_stmt),
3735 await_statement_walker, d, NULL);
3736 *do_subtree = 0; /* Done subtrees. */
3737 return res;
3738 }
3739 break;
3740 case DO_STMT:
3741 {
3742 /* We turn do stmt while (cond with awaits) into:
3743 do {
3744 stmt..
3745 if (!(cond with awaits))
3746 break;
3747 } while (true); */
3748 tree do_stmt = *stmt;
3749 if ((res = cp_walk_tree (&DO_COND (do_stmt),
3750 analyze_expression_awaits, d, &visited)))
3751 return res;
3752 if (!awpts->saw_awaits)
3753 return NULL_TREE; /* Nothing special to do here. */
3754
3755 tree insert_list = push_stmt_list ();
3756 /* The original do stmt body. */
3757 add_stmt (DO_BODY (do_stmt));
3758 coro_build_add_if_not_cond_break (DO_COND (do_stmt));
3759 /* The new while body. */
3760 DO_BODY (do_stmt) = pop_stmt_list (insert_list);
3761 DO_COND (do_stmt) = boolean_true_node;
3762 /* So now walk the new statement list. */
3763 res = cp_walk_tree (&DO_BODY (do_stmt), await_statement_walker,
3764 d, NULL);
3765 *do_subtree = 0; /* Done subtrees. */
3766 return res;
3767 }
3768 break;
3769 case SWITCH_STMT:
3770 {
3771 /* We turn 'switch (cond with awaits) stmt' into
3772 switch_type cond = cond with awaits
3773 switch (cond) stmt. */
3774 tree sw_stmt = *stmt;
3775 if ((res = cp_walk_tree (&SWITCH_STMT_COND (sw_stmt),
3776 analyze_expression_awaits, d, &visited)))
3777 return res;
3778 if (!awpts->saw_awaits)
3779 return NULL_TREE; /* Nothing special to do here. */
3780
3781 gcc_checking_assert (!awpts->bind_stack->is_empty());
3782 /* Build a variable to hold the condition, this will be
3783 included in the frame as a local var. */
3784 tree& bind_expr = awpts->bind_stack->last ();
3785 tree sw_type = SWITCH_STMT_TYPE (sw_stmt);
3786 tree newvar = add_var_to_bind (bind_expr, sw_type, "swch",
3787 awpts->cond_number++);
3788 tree insert_list = push_stmt_list ();
3789 add_decl_expr (newvar);
3790
3791 tree cond_inner = SWITCH_STMT_COND (sw_stmt);
3792 if (TREE_CODE (cond_inner) == CLEANUP_POINT_EXPR)
3793 cond_inner = TREE_OPERAND (cond_inner, 0);
3794 location_t sloc = EXPR_LOCATION (SWITCH_STMT_COND (sw_stmt));
3795 tree new_s = build2_loc (sloc, INIT_EXPR, sw_type, newvar,
3796 cond_inner);
3797 finish_expr_stmt (new_s);
3798 SWITCH_STMT_COND (sw_stmt) = newvar;
3799 /* Now add the switch statement with the condition re-
3800 written to use the local var. */
3801 add_stmt (sw_stmt);
3802 *stmt = pop_stmt_list (insert_list);
3803 /* Process the expanded list. */
3804 res = cp_walk_tree (stmt, await_statement_walker,
3805 d, NULL);
3806 *do_subtree = 0; /* Done subtrees. */
3807 return res;
3808 }
3809 break;
3810 case CO_RETURN_EXPR:
3811 {
3812 /* Expand the co_return as per [stmt.return.coroutine]
3813 - for co_return;
3814 { p.return_void (); goto final_suspend; }
3815 - for co_return [void expr];
3816 { expr; p.return_void(); goto final_suspend;}
3817 - for co_return [non void expr];
3818 { p.return_value(expr); goto final_suspend; } */
3819 if ((res = cp_walk_tree (stmt, analyze_expression_awaits,
3820 d, &visited)))
3821 return res;
3822 location_t loc = EXPR_LOCATION (expr);
3823 tree call = TREE_OPERAND (expr, 1);
3824 expr = TREE_OPERAND (expr, 0);
3825 tree ret_list = push_stmt_list ();
3826 /* [stmt.return.coroutine], 2.2
3827 If expr is present and void, it is placed immediately before
3828 the call for return_void; */
3829 tree *maybe_await_stmt = NULL;
3830 if (expr && VOID_TYPE_P (TREE_TYPE (expr)))
3831 {
3832 finish_expr_stmt (expr);
3833 /* If the return argument was a void expression, then any
3834 awaits must be contained in that. */
3835 maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list));
3836 }
3837 /* Insert p.return_{void,value(expr)}. */
3838 finish_expr_stmt (call);
3839 /* Absent a return of a void expression, any awaits must be in
3840 the parameter to return_value(). */
3841 if (!maybe_await_stmt)
3842 maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list));
3843 expr = build1_loc (loc, GOTO_EXPR, void_type_node, awpts->fs_label);
3844 finish_expr_stmt (expr);
3845 *stmt = pop_stmt_list (ret_list);
3846 /* Once this is complete, we will have processed subtrees. */
3847 *do_subtree = 0;
3848 if (awpts->saw_awaits)
3849 {
3850 gcc_checking_assert (maybe_await_stmt);
3851 res = cp_walk_tree (maybe_await_stmt, await_statement_walker,
3852 d, NULL);
3853 if (res)
3854 return res;
3855 }
3856 return NULL_TREE; /* Done. */
3857 }
3858 break;
3859 }
3860 else if (EXPR_P (expr))
3861 {
3862 if ((res = cp_walk_tree (stmt, analyze_expression_awaits, d, &visited)))
3863 return res;
3864 *do_subtree = 0; /* Done subtrees. */
3865 if (!awpts->saw_awaits)
3866 return NULL_TREE; /* Nothing special to do here. */
3867
3868 if (awpts->needs_truth_if_exp)
3869 {
3870 /* If a truth-and/or-if expression has an await expression in the
3871 conditionally-taken branch, then it must be rewritten into a
3872 regular conditional. */
3873 truth_if_transform xf = {stmt, NULL_TREE, &truth_aoif_to_expand};
3874 if ((res = cp_walk_tree (stmt, expand_one_truth_if, &xf, NULL)))
3875 return res;
3876 }
3877 /* Process this statement, which contains at least one await expression
3878 to 'promote' temporary values to a coroutine frame slot. */
3879 return maybe_promote_temps (stmt, d);
3880 }
3881 /* Continue recursion, if needed. */
3882 return res;
3883 }
3884
3885 /* For figuring out what param usage we have. */
3886
3887 struct param_frame_data
3888 {
3889 tree *field_list;
3890 hash_map<tree, param_info> *param_uses;
3891 hash_set<tree *> *visited;
3892 location_t loc;
3893 bool param_seen;
3894 };
3895
3896 /* A tree-walk callback that records the use of parameters (to allow for
3897 optimizations where handling unused parameters may be omitted). */
3898
3899 static tree
register_param_uses(tree * stmt,int * do_subtree ATTRIBUTE_UNUSED,void * d)3900 register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d)
3901 {
3902 param_frame_data *data = (param_frame_data *) d;
3903
3904 /* For lambda closure content, we have to look specifically. */
3905 if (TREE_CODE (*stmt) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*stmt))
3906 {
3907 tree t = DECL_VALUE_EXPR (*stmt);
3908 return cp_walk_tree (&t, register_param_uses, d, NULL);
3909 }
3910
3911 if (TREE_CODE (*stmt) != PARM_DECL)
3912 return NULL_TREE;
3913
3914 /* If we already saw the containing expression, then we're done. */
3915 if (data->visited->add (stmt))
3916 return NULL_TREE;
3917
3918 bool existed;
3919 param_info &parm = data->param_uses->get_or_insert (*stmt, &existed);
3920 gcc_checking_assert (existed);
3921
3922 if (!parm.body_uses)
3923 {
3924 vec_alloc (parm.body_uses, 4);
3925 parm.body_uses->quick_push (stmt);
3926 data->param_seen = true;
3927 }
3928 else
3929 parm.body_uses->safe_push (stmt);
3930
3931 return NULL_TREE;
3932 }
3933
3934 /* Small helper for the repetitive task of adding a new field to the coro
3935 frame type. */
3936
3937 static tree
coro_make_frame_entry(tree * field_list,const char * name,tree fld_type,location_t loc)3938 coro_make_frame_entry (tree *field_list, const char *name, tree fld_type,
3939 location_t loc)
3940 {
3941 tree id = get_identifier (name);
3942 tree decl = build_decl (loc, FIELD_DECL, id, fld_type);
3943 DECL_CHAIN (decl) = *field_list;
3944 *field_list = decl;
3945 return id;
3946 }
3947
3948 /* For recording local variable usage. */
3949
3950 struct local_vars_frame_data
3951 {
3952 tree *field_list;
3953 hash_map<tree, local_var_info> *local_var_uses;
3954 unsigned int nest_depth, bind_indx;
3955 location_t loc;
3956 bool saw_capture;
3957 bool local_var_seen;
3958 };
3959
3960 /* A tree-walk callback that processes one bind expression noting local
3961 variables, and making a coroutine frame slot available for those that
3962 need it, so that they can be 'promoted' across suspension points. */
3963
3964 static tree
register_local_var_uses(tree * stmt,int * do_subtree,void * d)3965 register_local_var_uses (tree *stmt, int *do_subtree, void *d)
3966 {
3967 local_vars_frame_data *lvd = (local_vars_frame_data *) d;
3968
3969 /* As we enter a bind expression - record the vars there and then recurse.
3970 As we exit drop the nest depth.
3971 The bind index is a growing count of how many bind indices we've seen.
3972 We build a space in the frame for each local var. */
3973
3974 if (TREE_CODE (*stmt) == BIND_EXPR)
3975 {
3976 lvd->bind_indx++;
3977 lvd->nest_depth++;
3978 tree lvar;
3979 for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL;
3980 lvar = DECL_CHAIN (lvar))
3981 {
3982 bool existed;
3983 local_var_info &local_var
3984 = lvd->local_var_uses->get_or_insert (lvar, &existed);
3985 gcc_checking_assert (!existed);
3986 local_var.def_loc = DECL_SOURCE_LOCATION (lvar);
3987 tree lvtype = TREE_TYPE (lvar);
3988 local_var.frame_type = lvtype;
3989 local_var.field_idx = local_var.field_id = NULL_TREE;
3990
3991 /* Make sure that we only present vars to the tests below. */
3992 if (TREE_CODE (lvar) == TYPE_DECL
3993 || TREE_CODE (lvar) == NAMESPACE_DECL)
3994 continue;
3995
3996 /* We don't move static vars into the frame. */
3997 local_var.is_static = TREE_STATIC (lvar);
3998 if (local_var.is_static)
3999 continue;
4000
4001 lvd->local_var_seen = true;
4002 /* If this var is a lambda capture proxy, we want to leave it alone,
4003 and later rewrite the DECL_VALUE_EXPR to indirect through the
4004 frame copy of the pointer to the lambda closure object. */
4005 local_var.is_lambda_capture = is_capture_proxy (lvar);
4006 if (local_var.is_lambda_capture)
4007 continue;
4008
4009 /* If a variable has a value expression, then that's what needs
4010 to be processed. */
4011 local_var.has_value_expr_p = DECL_HAS_VALUE_EXPR_P (lvar);
4012 if (local_var.has_value_expr_p)
4013 continue;
4014
4015 /* Make names depth+index unique, so that we can support nested
4016 scopes with identically named locals. */
4017 tree lvname = DECL_NAME (lvar);
4018 char *buf;
4019 if (lvname != NULL_TREE)
4020 buf = xasprintf ("__%s.%u.%u", IDENTIFIER_POINTER (lvname),
4021 lvd->nest_depth, lvd->bind_indx);
4022 else
4023 buf = xasprintf ("_D%u.%u.%u", DECL_UID (lvar), lvd->nest_depth,
4024 lvd->bind_indx);
4025 /* TODO: Figure out if we should build a local type that has any
4026 excess alignment or size from the original decl. */
4027 local_var.field_id
4028 = coro_make_frame_entry (lvd->field_list, buf, lvtype, lvd->loc);
4029 free (buf);
4030 /* We don't walk any of the local var sub-trees, they won't contain
4031 any bind exprs. */
4032 }
4033 cp_walk_tree (&BIND_EXPR_BODY (*stmt), register_local_var_uses, d, NULL);
4034 *do_subtree = 0; /* We've done this. */
4035 lvd->nest_depth--;
4036 }
4037 return NULL_TREE;
4038 }
4039
4040 /* Build, return FUNCTION_DECL node based on ORIG with a type FN_TYPE which has
4041 a single argument of type CORO_FRAME_PTR. Build the actor function if
4042 ACTOR_P is true, otherwise the destroy. */
4043
4044 static tree
coro_build_actor_or_destroy_function(tree orig,tree fn_type,tree coro_frame_ptr,bool actor_p)4045 coro_build_actor_or_destroy_function (tree orig, tree fn_type,
4046 tree coro_frame_ptr, bool actor_p)
4047 {
4048 location_t loc = DECL_SOURCE_LOCATION (orig);
4049 tree fn
4050 = build_lang_decl (FUNCTION_DECL, copy_node (DECL_NAME (orig)), fn_type);
4051
4052 /* Allow for locating the ramp (original) function from this one. */
4053 if (!to_ramp)
4054 to_ramp = hash_map<tree, tree>::create_ggc (10);
4055 to_ramp->put (fn, orig);
4056
4057 DECL_CONTEXT (fn) = DECL_CONTEXT (orig);
4058 DECL_SOURCE_LOCATION (fn) = loc;
4059 DECL_ARTIFICIAL (fn) = true;
4060 DECL_INITIAL (fn) = error_mark_node;
4061
4062 tree id = get_identifier ("frame_ptr");
4063 tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr);
4064 DECL_CONTEXT (fp) = fn;
4065 DECL_ARG_TYPE (fp) = type_passed_as (coro_frame_ptr);
4066 DECL_ARGUMENTS (fn) = fp;
4067
4068 /* Copy selected attributes from the original function. */
4069 TREE_USED (fn) = TREE_USED (orig);
4070 if (DECL_SECTION_NAME (orig))
4071 set_decl_section_name (fn, orig);
4072 /* Copy any alignment that the FE added. */
4073 if (DECL_ALIGN (orig))
4074 SET_DECL_ALIGN (fn, DECL_ALIGN (orig));
4075 /* Copy any alignment the user added. */
4076 DECL_USER_ALIGN (fn) = DECL_USER_ALIGN (orig);
4077 /* Apply attributes from the original fn. */
4078 DECL_ATTRIBUTES (fn) = copy_list (DECL_ATTRIBUTES (orig));
4079
4080 /* A void return. */
4081 tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node);
4082 DECL_CONTEXT (resdecl) = fn;
4083 DECL_ARTIFICIAL (resdecl) = 1;
4084 DECL_IGNORED_P (resdecl) = 1;
4085 DECL_RESULT (fn) = resdecl;
4086
4087 /* This is a coroutine component. */
4088 DECL_COROUTINE_P (fn) = 1;
4089
4090 /* Set up a means to find out if a decl is one of the helpers and, if so,
4091 which one. */
4092 if (coroutine_info *info = get_coroutine_info (orig))
4093 {
4094 gcc_checking_assert ((actor_p && info->actor_decl == NULL_TREE)
4095 || info->destroy_decl == NULL_TREE);
4096 if (actor_p)
4097 info->actor_decl = fn;
4098 else
4099 info->destroy_decl = fn;
4100 }
4101 return fn;
4102 }
4103
4104 /* Re-write the body as per [dcl.fct.def.coroutine] / 5. */
4105
4106 static tree
coro_rewrite_function_body(location_t fn_start,tree fnbody,tree orig,tree resume_fn_ptr_type,tree & resume_fn_field,tree & resume_idx_field,tree & fs_label)4107 coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig,
4108 tree resume_fn_ptr_type, tree& resume_fn_field,
4109 tree& resume_idx_field, tree& fs_label)
4110 {
4111 /* This will be our new outer scope. */
4112 tree update_body = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
4113 tree top_block = make_node (BLOCK);
4114 BIND_EXPR_BLOCK (update_body) = top_block;
4115 BIND_EXPR_BODY (update_body) = push_stmt_list ();
4116
4117 /* If the function has a top level bind expression, then connect that
4118 after first making sure we give it a new block. */
4119 tree first = expr_first (fnbody);
4120 if (first && TREE_CODE (first) == BIND_EXPR)
4121 {
4122 tree block = BIND_EXPR_BLOCK (first);
4123 gcc_checking_assert (block);
4124 gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
4125 gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE);
4126 /* Replace the top block to avoid issues with locations for args
4127 appearing to be in a non-existent place. */
4128 tree replace_blk = make_node (BLOCK);
4129 BLOCK_VARS (replace_blk) = BLOCK_VARS (block);
4130 BLOCK_SUBBLOCKS (replace_blk) = BLOCK_SUBBLOCKS (block);
4131 for (tree b = BLOCK_SUBBLOCKS (replace_blk); b; b = BLOCK_CHAIN (b))
4132 BLOCK_SUPERCONTEXT (b) = replace_blk;
4133 BIND_EXPR_BLOCK (first) = replace_blk;
4134 /* The top block has one child, so far, and we have now got a
4135 superblock. */
4136 BLOCK_SUPERCONTEXT (replace_blk) = top_block;
4137 BLOCK_SUBBLOCKS (top_block) = replace_blk;
4138 }
4139
4140 /* Wrap the function body in a try {} catch (...) {} block, if exceptions
4141 are enabled. */
4142 tree promise = get_coroutine_promise_proxy (orig);
4143 tree var_list = NULL_TREE;
4144 tree initial_await = build_init_or_final_await (fn_start, false);
4145
4146 /* [stmt.return.coroutine] / 3
4147 If p.return_void() is a valid expression, flowing off the end of a
4148 coroutine is equivalent to a co_return with no operand; otherwise
4149 flowing off the end of a coroutine results in undefined behavior. */
4150 tree return_void
4151 = get_coroutine_return_void_expr (current_function_decl, fn_start, false);
4152
4153 /* We will need to be able to set the resume function pointer to nullptr
4154 to signal that the coroutine is 'done'. */
4155 resume_fn_field
4156 = build_lang_decl (VAR_DECL, get_identifier ("resume.fn.ptr.proxy"),
4157 resume_fn_ptr_type);
4158 DECL_ARTIFICIAL (resume_fn_field) = true;
4159 tree zero_resume
4160 = build1 (CONVERT_EXPR, resume_fn_ptr_type, integer_zero_node);
4161 zero_resume
4162 = build2 (INIT_EXPR, resume_fn_ptr_type, resume_fn_field, zero_resume);
4163 /* Likewise, the resume index needs to be reset. */
4164 resume_idx_field
4165 = build_lang_decl (VAR_DECL, get_identifier ("resume.index.proxy"),
4166 short_unsigned_type_node);
4167 DECL_ARTIFICIAL (resume_idx_field) = true;
4168 tree zero_resume_idx = build_int_cst (short_unsigned_type_node, 0);
4169 zero_resume_idx = build2 (INIT_EXPR, short_unsigned_type_node,
4170 resume_idx_field, zero_resume_idx);
4171
4172 if (flag_exceptions)
4173 {
4174 /* Build promise.unhandled_exception(); */
4175 tree ueh
4176 = coro_build_promise_expression (current_function_decl, promise,
4177 coro_unhandled_exception_identifier,
4178 fn_start, NULL, /*musthave=*/true);
4179 /* Create and initialize the initial-await-resume-called variable per
4180 [dcl.fct.def.coroutine] / 5.3. */
4181 tree i_a_r_c = build_lang_decl (VAR_DECL, get_identifier ("i_a_r_c"),
4182 boolean_type_node);
4183 DECL_ARTIFICIAL (i_a_r_c) = true;
4184 DECL_CHAIN (i_a_r_c) = var_list;
4185 var_list = i_a_r_c;
4186 DECL_INITIAL (i_a_r_c) = boolean_false_node;
4187 add_decl_expr (i_a_r_c);
4188 /* Start the try-catch. */
4189 tree tcb = build_stmt (fn_start, TRY_BLOCK, NULL_TREE, NULL_TREE);
4190 add_stmt (tcb);
4191 TRY_STMTS (tcb) = push_stmt_list ();
4192 if (initial_await != error_mark_node)
4193 {
4194 /* Build a compound expression that sets the
4195 initial-await-resume-called variable true and then calls the
4196 initial suspend expression await resume. */
4197 tree vec = TREE_OPERAND (initial_await, 3);
4198 tree aw_r = TREE_VEC_ELT (vec, 2);
4199 tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c,
4200 boolean_true_node);
4201 aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error);
4202 TREE_VEC_ELT (vec, 2) = aw_r;
4203 }
4204 /* Add the initial await to the start of the user-authored function. */
4205 finish_expr_stmt (initial_await);
4206 /* Append the original function body. */
4207 add_stmt (fnbody);
4208 if (return_void)
4209 add_stmt (return_void);
4210 TRY_STMTS (tcb) = pop_stmt_list (TRY_STMTS (tcb));
4211 TRY_HANDLERS (tcb) = push_stmt_list ();
4212 /* Mimic what the parser does for the catch. */
4213 tree handler = begin_handler ();
4214 finish_handler_parms (NULL_TREE, handler); /* catch (...) */
4215
4216 /* Get the initial await resume called value. */
4217 tree not_iarc_if = begin_if_stmt ();
4218 tree not_iarc = build1_loc (fn_start, TRUTH_NOT_EXPR,
4219 boolean_type_node, i_a_r_c);
4220 finish_if_stmt_cond (not_iarc, not_iarc_if);
4221 /* If the initial await resume called value is false, rethrow... */
4222 tree rethrow = build_throw (fn_start, NULL_TREE);
4223 TREE_NO_WARNING (rethrow) = true;
4224 finish_expr_stmt (rethrow);
4225 finish_then_clause (not_iarc_if);
4226 tree iarc_scope = IF_SCOPE (not_iarc_if);
4227 IF_SCOPE (not_iarc_if) = NULL;
4228 not_iarc_if = do_poplevel (iarc_scope);
4229 add_stmt (not_iarc_if);
4230 /* ... else call the promise unhandled exception method
4231 but first we set done = true and the resume index to 0.
4232 If the unhandled exception method returns, then we continue
4233 to the final await expression (which duplicates the clearing of
4234 the field). */
4235 finish_expr_stmt (zero_resume);
4236 finish_expr_stmt (zero_resume_idx);
4237 ueh = maybe_cleanup_point_expr_void (ueh);
4238 add_stmt (ueh);
4239 finish_handler (handler);
4240 TRY_HANDLERS (tcb) = pop_stmt_list (TRY_HANDLERS (tcb));
4241 }
4242 else
4243 {
4244 if (pedantic)
4245 {
4246 /* We still try to look for the promise method and warn if it's not
4247 present. */
4248 tree ueh_meth
4249 = lookup_promise_method (orig, coro_unhandled_exception_identifier,
4250 fn_start, /*musthave=*/false);
4251 if (!ueh_meth || ueh_meth == error_mark_node)
4252 warning_at (fn_start, 0, "no member named %qE in %qT",
4253 coro_unhandled_exception_identifier,
4254 get_coroutine_promise_type (orig));
4255 }
4256 /* Else we don't check and don't care if the method is missing..
4257 just add the initial suspend, function and return. */
4258 finish_expr_stmt (initial_await);
4259 /* Append the original function body. */
4260 add_stmt (fnbody);
4261 if (return_void)
4262 add_stmt (return_void);
4263 }
4264
4265 /* co_return branches to the final_suspend label, so declare that now. */
4266 fs_label
4267 = create_named_label_with_ctx (fn_start, "final.suspend", NULL_TREE);
4268 add_stmt (build_stmt (fn_start, LABEL_EXPR, fs_label));
4269
4270 /* Before entering the final suspend point, we signal that this point has
4271 been reached by setting the resume function pointer to zero (this is
4272 what the 'done()' builtin tests) as per the current ABI. */
4273 finish_expr_stmt (zero_resume);
4274 finish_expr_stmt (build_init_or_final_await (fn_start, true));
4275 BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body));
4276 BIND_EXPR_VARS (update_body) = nreverse (var_list);
4277 BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body);
4278
4279 return update_body;
4280 }
4281
4282 /* Here we:
4283 a) Check that the function and promise type are valid for a
4284 coroutine.
4285 b) Carry out the initial morph to create the skeleton of the
4286 coroutine ramp function and the rewritten body.
4287
4288 Assumptions.
4289
4290 1. We only hit this code once all dependencies are resolved.
4291 2. The function body will be either a bind expr or a statement list
4292 3. That cfun and current_function_decl are valid for the case we're
4293 expanding.
4294 4. 'input_location' will be of the final brace for the function.
4295
4296 We do something like this:
4297 declare a dummy coro frame.
4298 struct _R_frame {
4299 using handle_type = coro::coroutine_handle<coro1::promise_type>;
4300 void (*__resume)(_R_frame *);
4301 void (*__destroy)(_R_frame *);
4302 coro1::promise_type __p;
4303 bool frame_needs_free; free the coro frame mem if set.
4304 bool i_a_r_c; [dcl.fct.def.coroutine] / 5.3
4305 short __resume_at;
4306 handle_type self_handle;
4307 (maybe) parameter copies.
4308 (maybe) local variables saved (including awaitables)
4309 (maybe) trailing space.
4310 }; */
4311
4312 bool
morph_fn_to_coro(tree orig,tree * resumer,tree * destroyer)4313 morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
4314 {
4315 gcc_checking_assert (orig && TREE_CODE (orig) == FUNCTION_DECL);
4316
4317 *resumer = error_mark_node;
4318 *destroyer = error_mark_node;
4319 if (!coro_function_valid_p (orig))
4320 {
4321 /* For early errors, we do not want a diagnostic about the missing
4322 ramp return value, since the user cannot fix this - a 'return' is
4323 not allowed in a coroutine. */
4324 TREE_NO_WARNING (orig) = true;
4325 /* Discard the body, we can't process it further. */
4326 pop_stmt_list (DECL_SAVED_TREE (orig));
4327 DECL_SAVED_TREE (orig) = push_stmt_list ();
4328 return false;
4329 }
4330
4331 /* We can't validly get here with an empty statement list, since there's no
4332 way for the FE to decide it's a coroutine in the absence of any code. */
4333 tree fnbody = pop_stmt_list (DECL_SAVED_TREE (orig));
4334 gcc_checking_assert (fnbody != NULL_TREE);
4335
4336 /* We don't have the locus of the opening brace - it's filled in later (and
4337 there doesn't really seem to be any easy way to get at it).
4338 The closing brace is assumed to be input_location. */
4339 location_t fn_start = DECL_SOURCE_LOCATION (orig);
4340 gcc_rich_location fn_start_loc (fn_start);
4341
4342 /* Initial processing of the function-body.
4343 If we have no expressions or just an error then punt. */
4344 tree body_start = expr_first (fnbody);
4345 if (body_start == NULL_TREE || body_start == error_mark_node)
4346 {
4347 DECL_SAVED_TREE (orig) = push_stmt_list ();
4348 append_to_statement_list (fnbody, &DECL_SAVED_TREE (orig));
4349 /* Suppress warnings about the missing return value. */
4350 TREE_NO_WARNING (orig) = true;
4351 return false;
4352 }
4353
4354 /* So, we've tied off the original user-authored body in fn_body.
4355
4356 Start the replacement synthesized ramp body as newbody.
4357 If we encounter a fatal error we might return a now-empty body.
4358
4359 Note, the returned ramp body is not 'popped', to be compatible with
4360 the way that decl.c handles regular functions, the scope pop is done
4361 in the caller. */
4362
4363 tree newbody = push_stmt_list ();
4364 DECL_SAVED_TREE (orig) = newbody;
4365
4366 /* If our original body is noexcept, then that's what we apply to our
4367 generated ramp, transfer any MUST_NOT_THOW_EXPR to that. */
4368 bool is_noexcept = TREE_CODE (body_start) == MUST_NOT_THROW_EXPR;
4369 if (is_noexcept)
4370 {
4371 /* The function body we will continue with is the single operand to
4372 the must-not-throw. */
4373 fnbody = TREE_OPERAND (body_start, 0);
4374 /* Transfer the must-not-throw to the ramp body. */
4375 add_stmt (body_start);
4376 /* Re-start the ramp as must-not-throw. */
4377 TREE_OPERAND (body_start, 0) = push_stmt_list ();
4378 }
4379
4380 /* If the original function has a return value with a non-trivial DTOR
4381 and the body contains a var with a DTOR that might throw, the decl is
4382 marked "throwing_cleanup".
4383 We do not [in the ramp, which is synthesised here], use any body var
4384 types with DTORs that might throw.
4385 The original body is transformed into the actor function which only
4386 contains void returns, and is also wrapped in a try-catch block.
4387 So (a) the 'throwing_cleanup' is not correct for the ramp and (b) we do
4388 not need to transfer it to the actor which only contains void returns. */
4389 cp_function_chain->throwing_cleanup = false;
4390
4391 /* Create the coro frame type, as far as it can be known at this stage.
4392 1. Types we already know. */
4393
4394 tree fn_return_type = TREE_TYPE (TREE_TYPE (orig));
4395 tree handle_type = get_coroutine_handle_type (orig);
4396 tree promise_type = get_coroutine_promise_type (orig);
4397
4398 /* 2. Types we need to define or look up. */
4399
4400 tree fr_name = get_fn_local_identifier (orig, "frame");
4401 tree coro_frame_type = xref_tag (record_type, fr_name);
4402 DECL_CONTEXT (TYPE_NAME (coro_frame_type)) = current_scope ();
4403 tree coro_frame_ptr = build_pointer_type (coro_frame_type);
4404 tree act_des_fn_type
4405 = build_function_type_list (void_type_node, coro_frame_ptr, NULL_TREE);
4406 tree act_des_fn_ptr = build_pointer_type (act_des_fn_type);
4407
4408 /* Declare the actor and destroyer function. */
4409 tree actor = coro_build_actor_or_destroy_function (orig, act_des_fn_type,
4410 coro_frame_ptr, true);
4411 tree destroy = coro_build_actor_or_destroy_function (orig, act_des_fn_type,
4412 coro_frame_ptr, false);
4413
4414 /* Construct the wrapped function body; we will analyze this to determine
4415 the requirements for the coroutine frame. */
4416
4417 tree resume_fn_field = NULL_TREE;
4418 tree resume_idx_field = NULL_TREE;
4419 tree fs_label = NULL_TREE;
4420 fnbody = coro_rewrite_function_body (fn_start, fnbody, orig,
4421 act_des_fn_ptr, resume_fn_field,
4422 resume_idx_field, fs_label);
4423 /* Build our dummy coro frame layout. */
4424 coro_frame_type = begin_class_definition (coro_frame_type);
4425
4426 tree field_list = NULL_TREE;
4427 tree resume_name
4428 = coro_make_frame_entry (&field_list, "__resume",
4429 act_des_fn_ptr, fn_start);
4430 tree destroy_name
4431 = coro_make_frame_entry (&field_list, "__destroy",
4432 act_des_fn_ptr, fn_start);
4433 tree promise_name
4434 = coro_make_frame_entry (&field_list, "__p", promise_type, fn_start);
4435 tree fnf_name = coro_make_frame_entry (&field_list, "__frame_needs_free",
4436 boolean_type_node, fn_start);
4437 tree resume_idx_name
4438 = coro_make_frame_entry (&field_list, "__resume_at",
4439 short_unsigned_type_node, fn_start);
4440
4441 /* We need a handle to this coroutine, which is passed to every
4442 await_suspend(). There's no point in creating it over and over. */
4443 (void) coro_make_frame_entry (&field_list, "__self_h", handle_type, fn_start);
4444
4445 /* Now add in fields for function params (if there are any).
4446 We do not attempt elision of copies at this stage, we do analyze the
4447 uses and build worklists to replace those when the state machine is
4448 lowered. */
4449
4450 hash_map<tree, param_info> *param_uses = NULL;
4451 if (DECL_ARGUMENTS (orig))
4452 {
4453 /* Build a hash map with an entry for each param.
4454 The key is the param tree.
4455 Then we have an entry for the frame field name.
4456 Then a cache for the field ref when we come to use it.
4457 Then a tree list of the uses.
4458 The second two entries start out empty - and only get populated
4459 when we see uses. */
4460 param_uses = new hash_map<tree, param_info>;
4461 bool lambda_p = LAMBDA_FUNCTION_P (orig);
4462
4463 unsigned no_name_parm = 0;
4464 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
4465 arg = DECL_CHAIN (arg))
4466 {
4467 bool existed;
4468 param_info &parm = param_uses->get_or_insert (arg, &existed);
4469 gcc_checking_assert (!existed);
4470 parm.body_uses = NULL;
4471 tree actual_type = TREE_TYPE (arg);
4472 actual_type = complete_type_or_else (actual_type, orig);
4473 if (actual_type == NULL_TREE)
4474 actual_type = error_mark_node;
4475 parm.orig_type = actual_type;
4476 parm.by_ref = parm.pt_ref = parm.rv_ref = false;
4477 if (TREE_CODE (actual_type) == REFERENCE_TYPE)
4478 {
4479 /* If the user passes by reference, then we will save the
4480 pointer to the original. As noted in
4481 [dcl.fct.def.coroutine] / 13, if the lifetime of the
4482 referenced item ends and then the coroutine is resumed,
4483 we have UB; well, the user asked for it. */
4484 if (TYPE_REF_IS_RVALUE (actual_type))
4485 parm.rv_ref = true;
4486 else
4487 parm.pt_ref = true;
4488 }
4489 else if (TYPE_REF_P (DECL_ARG_TYPE (arg)))
4490 parm.by_ref = true;
4491
4492 parm.frame_type = actual_type;
4493
4494 parm.this_ptr = is_this_parameter (arg);
4495 parm.lambda_cobj = lambda_p && DECL_NAME (arg) == closure_identifier;
4496
4497 char *buf;
4498 if (DECL_NAME (arg))
4499 {
4500 tree pname = DECL_NAME (arg);
4501 buf = xasprintf ("__parm.%s", IDENTIFIER_POINTER (pname));
4502 }
4503 else
4504 buf = xasprintf ("__unnamed_parm.%d", no_name_parm++);
4505
4506 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type))
4507 {
4508 char *gbuf = xasprintf ("%s.live", buf);
4509 parm.guard_var
4510 = build_lang_decl (VAR_DECL, get_identifier (gbuf),
4511 boolean_type_node);
4512 free (gbuf);
4513 DECL_ARTIFICIAL (parm.guard_var) = true;
4514 DECL_INITIAL (parm.guard_var) = boolean_false_node;
4515 parm.trivial_dtor = false;
4516 }
4517 else
4518 parm.trivial_dtor = true;
4519 parm.field_id = coro_make_frame_entry
4520 (&field_list, buf, actual_type, DECL_SOURCE_LOCATION (arg));
4521 free (buf);
4522 }
4523
4524 /* We want to record every instance of param's use, so don't include
4525 a 'visited' hash_set on the tree walk, but only record a containing
4526 expression once. */
4527 hash_set<tree *> visited;
4528 param_frame_data param_data
4529 = {&field_list, param_uses, &visited, fn_start, false};
4530 cp_walk_tree (&fnbody, register_param_uses, ¶m_data, NULL);
4531 }
4532
4533 /* We need to know, and inspect, each suspend point in the function
4534 in several places. It's convenient to place this map out of line
4535 since it's used from tree walk callbacks. */
4536 suspend_points = new hash_map<tree, suspend_point_info>;
4537
4538 /* Now insert the data for any body await points, at this time we also need
4539 to promote any temporaries that are captured by reference (to regular
4540 vars) they will get added to the coro frame along with other locals. */
4541 susp_frame_data body_aw_points
4542 = {&field_list, handle_type, fs_label, NULL, NULL, 0, 0,
4543 hash_set<tree> (), NULL, NULL, 0, false, false, false};
4544 body_aw_points.block_stack = make_tree_vector ();
4545 body_aw_points.bind_stack = make_tree_vector ();
4546 body_aw_points.to_replace = make_tree_vector ();
4547 cp_walk_tree (&fnbody, await_statement_walker, &body_aw_points, NULL);
4548
4549 /* 4. Now make space for local vars, this is conservative again, and we
4550 would expect to delete unused entries later. */
4551 hash_map<tree, local_var_info> local_var_uses;
4552 local_vars_frame_data local_vars_data
4553 = {&field_list, &local_var_uses, 0, 0, fn_start, false, false};
4554 cp_walk_tree (&fnbody, register_local_var_uses, &local_vars_data, NULL);
4555
4556 /* Tie off the struct for now, so that we can build offsets to the
4557 known entries. */
4558 TYPE_FIELDS (coro_frame_type) = field_list;
4559 TYPE_BINFO (coro_frame_type) = make_tree_binfo (0);
4560 BINFO_OFFSET (TYPE_BINFO (coro_frame_type)) = size_zero_node;
4561 BINFO_TYPE (TYPE_BINFO (coro_frame_type)) = coro_frame_type;
4562
4563 coro_frame_type = finish_struct (coro_frame_type, NULL_TREE);
4564
4565 /* Ramp: */
4566 /* Now build the ramp function pieces. */
4567 tree ramp_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
4568 add_stmt (ramp_bind);
4569 tree ramp_body = push_stmt_list ();
4570
4571 tree coro_fp = build_lang_decl (VAR_DECL, get_identifier ("coro.frameptr"),
4572 coro_frame_ptr);
4573 tree varlist = coro_fp;
4574
4575 /* To signal that we need to cleanup copied function args. */
4576 if (flag_exceptions && DECL_ARGUMENTS (orig))
4577 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
4578 arg = DECL_CHAIN (arg))
4579 {
4580 param_info *parm_i = param_uses->get (arg);
4581 gcc_checking_assert (parm_i);
4582 if (parm_i->trivial_dtor)
4583 continue;
4584 DECL_CHAIN (parm_i->guard_var) = varlist;
4585 varlist = parm_i->guard_var;
4586 }
4587
4588 /* Signal that we need to clean up the promise object on exception. */
4589 tree coro_promise_live
4590 = build_lang_decl (VAR_DECL, get_identifier ("coro.promise.live"),
4591 boolean_type_node);
4592 DECL_ARTIFICIAL (coro_promise_live) = true;
4593 DECL_CHAIN (coro_promise_live) = varlist;
4594 varlist = coro_promise_live;
4595 DECL_INITIAL (coro_promise_live) = boolean_false_node;
4596 /* When the get-return-object is in the RETURN slot, we need to arrange for
4597 cleanup on exception. */
4598 tree coro_gro_live
4599 = build_lang_decl (VAR_DECL, get_identifier ("coro.gro.live"),
4600 boolean_type_node);
4601 DECL_ARTIFICIAL (coro_gro_live) = true;
4602 DECL_CHAIN (coro_gro_live) = varlist;
4603 varlist = coro_gro_live;
4604 DECL_INITIAL (coro_gro_live) = boolean_false_node;
4605
4606 /* Collected the scope vars we need ... only one for now. */
4607 BIND_EXPR_VARS (ramp_bind) = nreverse (varlist);
4608
4609 /* We're now going to create a new top level scope block for the ramp
4610 function. */
4611 tree top_block = make_node (BLOCK);
4612
4613 BIND_EXPR_BLOCK (ramp_bind) = top_block;
4614 BLOCK_VARS (top_block) = BIND_EXPR_VARS (ramp_bind);
4615 BLOCK_SUBBLOCKS (top_block) = NULL_TREE;
4616
4617 /* The decl_expr for the coro frame pointer, initialize to zero so that we
4618 can pass it to the IFN_CO_FRAME (since there's no way to pass a type,
4619 directly apparently). This avoids a "used uninitialized" warning. */
4620 tree zeroinit = build1 (CONVERT_EXPR, coro_frame_ptr, integer_zero_node);
4621 DECL_INITIAL (coro_fp) = zeroinit;
4622 add_decl_expr (coro_fp);
4623 if (flag_exceptions && DECL_ARGUMENTS (orig))
4624 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
4625 arg = DECL_CHAIN (arg))
4626 {
4627 param_info *parm_i = param_uses->get (arg);
4628 if (parm_i->trivial_dtor)
4629 continue;
4630 add_decl_expr (parm_i->guard_var);;
4631 }
4632 add_decl_expr (coro_promise_live);
4633 add_decl_expr (coro_gro_live);
4634
4635 /* The CO_FRAME internal function is a mechanism to allow the middle end
4636 to adjust the allocation in response to optimizations. We provide the
4637 current conservative estimate of the frame size (as per the current)
4638 computed layout. */
4639 tree frame_size = TYPE_SIZE_UNIT (coro_frame_type);
4640 tree resizeable
4641 = build_call_expr_internal_loc (fn_start, IFN_CO_FRAME, size_type_node, 2,
4642 frame_size, coro_fp);
4643
4644 /* [dcl.fct.def.coroutine] / 10 (part1)
4645 The unqualified-id get_return_object_on_allocation_failure is looked up
4646 in the scope of the promise type by class member access lookup. */
4647
4648 /* We don't require this, so coro_build_promise_expression can return NULL,
4649 but, if the lookup succeeds, then the function must be usable. */
4650 tree dummy_promise = build_dummy_object (get_coroutine_promise_type (orig));
4651 tree grooaf
4652 = coro_build_promise_expression (orig, dummy_promise,
4653 coro_gro_on_allocation_fail_identifier,
4654 fn_start, NULL, /*musthave=*/false);
4655
4656 /* however, should that fail, returning an error, the later stages can't
4657 handle the erroneous expression, so we reset the call as if it was
4658 absent. */
4659 if (grooaf == error_mark_node)
4660 grooaf = NULL_TREE;
4661
4662 /* Allocate the frame, this has several possibilities:
4663 [dcl.fct.def.coroutine] / 9 (part 1)
4664 The allocation function’s name is looked up in the scope of the promise
4665 type. It's not a failure for it to be absent see part 4, below. */
4666
4667 tree nwname = ovl_op_identifier (false, NEW_EXPR);
4668 tree new_fn = NULL_TREE;
4669
4670 if (TYPE_HAS_NEW_OPERATOR (promise_type))
4671 {
4672 tree fns = lookup_promise_method (orig, nwname, fn_start,
4673 /*musthave=*/true);
4674 /* [dcl.fct.def.coroutine] / 9 (part 2)
4675 If the lookup finds an allocation function in the scope of the promise
4676 type, overload resolution is performed on a function call created by
4677 assembling an argument list. The first argument is the amount of space
4678 requested, and has type std::size_t. The succeeding arguments are
4679 those of the original function. */
4680 vec<tree, va_gc> *args = make_tree_vector ();
4681 vec_safe_push (args, resizeable); /* Space needed. */
4682
4683 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
4684 arg = DECL_CHAIN (arg))
4685 {
4686 param_info *parm_i = param_uses->get (arg);
4687 gcc_checking_assert (parm_i);
4688 if (parm_i->this_ptr || parm_i->lambda_cobj)
4689 {
4690 /* We pass a reference to *this to the allocator lookup. */
4691 tree tt = TREE_TYPE (TREE_TYPE (arg));
4692 tree this_ref = build1 (INDIRECT_REF, tt, arg);
4693 tt = cp_build_reference_type (tt, false);
4694 this_ref = convert_to_reference (tt, this_ref, CONV_STATIC,
4695 LOOKUP_NORMAL , NULL_TREE,
4696 tf_warning_or_error);
4697 vec_safe_push (args, this_ref);
4698 }
4699 else
4700 vec_safe_push (args, arg);
4701 }
4702
4703 /* Note the function selected; we test to see if it's NOTHROW. */
4704 tree func;
4705 /* Failure is not an error for this attempt. */
4706 new_fn = build_new_method_call (dummy_promise, fns, &args, NULL,
4707 LOOKUP_NORMAL, &func, tf_none);
4708 release_tree_vector (args);
4709
4710 if (new_fn == error_mark_node)
4711 {
4712 /* [dcl.fct.def.coroutine] / 9 (part 3)
4713 If no viable function is found, overload resolution is performed
4714 again on a function call created by passing just the amount of
4715 space required as an argument of type std::size_t. */
4716 args = make_tree_vector_single (resizeable); /* Space needed. */
4717 new_fn = build_new_method_call (dummy_promise, fns, &args,
4718 NULL_TREE, LOOKUP_NORMAL, &func,
4719 tf_none);
4720 release_tree_vector (args);
4721 }
4722
4723 /* However, if the promise provides an operator new, then one of these
4724 two options must be available. */
4725 if (new_fn == error_mark_node)
4726 {
4727 error_at (fn_start, "%qE is provided by %qT but is not usable with"
4728 " the function signature %qD", nwname, promise_type, orig);
4729 new_fn = error_mark_node;
4730 }
4731 else if (grooaf && !TYPE_NOTHROW_P (TREE_TYPE (func)))
4732 error_at (fn_start, "%qE is provided by %qT but %qE is not marked"
4733 " %<throw()%> or %<noexcept%>", grooaf, promise_type, nwname);
4734 else if (!grooaf && TYPE_NOTHROW_P (TREE_TYPE (func)))
4735 warning_at (fn_start, 0, "%qE is marked %<throw()%> or %<noexcept%> but"
4736 " no usable %<get_return_object_on_allocation_failure%>"
4737 " is provided by %qT", nwname, promise_type);
4738 }
4739 else /* No operator new in the promise. */
4740 {
4741 /* [dcl.fct.def.coroutine] / 9 (part 4)
4742 If this lookup fails, the allocation function’s name is looked up in
4743 the global scope. */
4744
4745 vec<tree, va_gc> *args;
4746 /* build_operator_new_call () will insert size needed as element 0 of
4747 this, and we might need to append the std::nothrow constant. */
4748 vec_alloc (args, 2);
4749 if (grooaf)
4750 {
4751 /* [dcl.fct.def.coroutine] / 10 (part 2)
4752 If any declarations (of the get return on allocation fail) are
4753 found, then the result of a call to an allocation function used
4754 to obtain storage for the coroutine state is assumed to return
4755 nullptr if it fails to obtain storage and, if a global allocation
4756 function is selected, the ::operator new(size_t, nothrow_t) form
4757 is used. The allocation function used in this case shall have a
4758 non-throwing noexcept-specification. So we need std::nothrow. */
4759 tree std_nt = lookup_qualified_name (std_node,
4760 get_identifier ("nothrow"),
4761 LOOK_want::NORMAL,
4762 /*complain=*/true);
4763 if (!std_nt || std_nt == error_mark_node)
4764 error_at (fn_start, "%qE is provided by %qT but %<std::nothrow%> "
4765 "cannot be found", grooaf, promise_type);
4766 vec_safe_push (args, std_nt);
4767 }
4768
4769 /* If we get to this point, we must succeed in looking up the global
4770 operator new for the params provided. Extract a simplified version
4771 of the machinery from build_operator_new_call. This can update the
4772 frame size. */
4773 tree cookie = NULL;
4774 new_fn = build_operator_new_call (nwname, &args, &frame_size, &cookie,
4775 /*align_arg=*/NULL,
4776 /*size_check=*/NULL, /*fn=*/NULL,
4777 tf_warning_or_error);
4778 resizeable = build_call_expr_internal_loc
4779 (fn_start, IFN_CO_FRAME, size_type_node, 2, frame_size, coro_fp);
4780 /* If the operator call fails for some reason, then don't try to
4781 amend it. */
4782 if (new_fn != error_mark_node)
4783 CALL_EXPR_ARG (new_fn, 0) = resizeable;
4784
4785 release_tree_vector (args);
4786 }
4787
4788 tree allocated = build1 (CONVERT_EXPR, coro_frame_ptr, new_fn);
4789 tree r = build2 (INIT_EXPR, TREE_TYPE (coro_fp), coro_fp, allocated);
4790 r = coro_build_cvt_void_expr_stmt (r, fn_start);
4791 add_stmt (r);
4792
4793 /* If the user provided a method to return an object on alloc fail, then
4794 check the returned pointer and call the func if it's null.
4795 Otherwise, no check, and we fail for noexcept/fno-exceptions cases. */
4796
4797 if (grooaf)
4798 {
4799 /* [dcl.fct.def.coroutine] / 10 (part 3)
4800 If the allocation function returns nullptr,the coroutine returns
4801 control to the caller of the coroutine and the return value is
4802 obtained by a call to T::get_return_object_on_allocation_failure(),
4803 where T is the promise type. */
4804
4805 gcc_checking_assert (same_type_p (fn_return_type, TREE_TYPE (grooaf)));
4806 tree if_stmt = begin_if_stmt ();
4807 tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, integer_zero_node);
4808 cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
4809 finish_if_stmt_cond (cond, if_stmt);
4810 if (VOID_TYPE_P (fn_return_type))
4811 {
4812 /* Execute the get-return-object-on-alloc-fail call... */
4813 finish_expr_stmt (grooaf);
4814 /* ... but discard the result, since we return void. */
4815 finish_return_stmt (NULL_TREE);
4816 }
4817 else
4818 {
4819 /* Get the fallback return object. */
4820 r = build_cplus_new (fn_return_type, grooaf, tf_warning_or_error);
4821 finish_return_stmt (r);
4822 }
4823 finish_then_clause (if_stmt);
4824 finish_if_stmt (if_stmt);
4825 }
4826
4827 /* Up to now any exception thrown will propagate directly to the caller.
4828 This is OK since the only source of such exceptions would be in allocation
4829 of the coroutine frame, and therefore the ramp will not have initialized
4830 any further state. From here, we will track state that needs explicit
4831 destruction in the case that promise or g.r.o setup fails or an exception
4832 is thrown from the initial suspend expression. */
4833 tree ramp_cleanup = NULL_TREE;
4834 if (flag_exceptions)
4835 {
4836 ramp_cleanup = build_stmt (fn_start, TRY_BLOCK, NULL, NULL);
4837 add_stmt (ramp_cleanup);
4838 TRY_STMTS (ramp_cleanup) = push_stmt_list ();
4839 }
4840
4841 /* deref the frame pointer, to use in member access code. */
4842 tree deref_fp = build_x_arrow (fn_start, coro_fp, tf_warning_or_error);
4843
4844 /* For now, once allocation has succeeded we always assume that this needs
4845 destruction, there's no impl. for frame allocation elision. */
4846 tree fnf_m
4847 = lookup_member (coro_frame_type, fnf_name, 1, 0, tf_warning_or_error);
4848 tree fnf_x = build_class_member_access_expr (deref_fp, fnf_m, NULL_TREE,
4849 false, tf_warning_or_error);
4850 r = build2 (INIT_EXPR, boolean_type_node, fnf_x, boolean_true_node);
4851 r = coro_build_cvt_void_expr_stmt (r, fn_start);
4852 add_stmt (r);
4853
4854 /* Put the resumer and destroyer functions in. */
4855
4856 tree actor_addr = build1 (ADDR_EXPR, act_des_fn_ptr, actor);
4857 tree resume_m
4858 = lookup_member (coro_frame_type, resume_name,
4859 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
4860 tree resume_x = build_class_member_access_expr (deref_fp, resume_m, NULL_TREE,
4861 false, tf_warning_or_error);
4862 r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, resume_x, actor_addr);
4863 r = coro_build_cvt_void_expr_stmt (r, fn_start);
4864 add_stmt (r);
4865
4866 tree destroy_addr = build1 (ADDR_EXPR, act_des_fn_ptr, destroy);
4867 tree destroy_m
4868 = lookup_member (coro_frame_type, destroy_name,
4869 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
4870 tree destroy_x
4871 = build_class_member_access_expr (deref_fp, destroy_m, NULL_TREE, false,
4872 tf_warning_or_error);
4873 r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, destroy_x, destroy_addr);
4874 r = coro_build_cvt_void_expr_stmt (r, fn_start);
4875 add_stmt (r);
4876
4877 /* [dcl.fct.def.coroutine] /13
4878 When a coroutine is invoked, a copy is created for each coroutine
4879 parameter. Each such copy is an object with automatic storage duration
4880 that is direct-initialized from an lvalue referring to the corresponding
4881 parameter if the parameter is an lvalue reference, and from an xvalue
4882 referring to it otherwise. A reference to a parameter in the function-
4883 body of the coroutine and in the call to the coroutine promise
4884 constructor is replaced by a reference to its copy. */
4885
4886 vec<tree, va_gc> *promise_args = NULL; /* So that we can adjust refs. */
4887
4888 /* The initialization and destruction of each parameter copy occurs in the
4889 context of the called coroutine. Initializations of parameter copies are
4890 sequenced before the call to the coroutine promise constructor and
4891 indeterminately sequenced with respect to each other. The lifetime of
4892 parameter copies ends immediately after the lifetime of the coroutine
4893 promise object ends. */
4894
4895 vec<tree, va_gc> *param_dtor_list = NULL;
4896
4897 if (DECL_ARGUMENTS (orig))
4898 {
4899 promise_args = make_tree_vector ();
4900 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
4901 arg = DECL_CHAIN (arg))
4902 {
4903 bool existed;
4904 param_info &parm = param_uses->get_or_insert (arg, &existed);
4905
4906 tree fld_ref = lookup_member (coro_frame_type, parm.field_id,
4907 /*protect=*/1, /*want_type=*/0,
4908 tf_warning_or_error);
4909 tree fld_idx
4910 = build_class_member_access_expr (deref_fp, fld_ref, NULL_TREE,
4911 false, tf_warning_or_error);
4912
4913 /* Add this to the promise CTOR arguments list, accounting for
4914 refs and special handling for method this ptr. */
4915 if (parm.this_ptr || parm.lambda_cobj)
4916 {
4917 /* We pass a reference to *this to the param preview. */
4918 tree tt = TREE_TYPE (arg);
4919 gcc_checking_assert (POINTER_TYPE_P (tt));
4920 tree ct = TREE_TYPE (tt);
4921 tree this_ref = build1 (INDIRECT_REF, ct, arg);
4922 tree rt = cp_build_reference_type (ct, false);
4923 this_ref = convert_to_reference (rt, this_ref, CONV_STATIC,
4924 LOOKUP_NORMAL, NULL_TREE,
4925 tf_warning_or_error);
4926 vec_safe_push (promise_args, this_ref);
4927 }
4928 else if (parm.rv_ref)
4929 vec_safe_push (promise_args, rvalue(fld_idx));
4930 else
4931 vec_safe_push (promise_args, fld_idx);
4932
4933 if (parm.rv_ref || parm.pt_ref)
4934 /* Initialise the frame reference field directly. */
4935 r = build_modify_expr (fn_start, TREE_OPERAND (fld_idx, 0),
4936 parm.frame_type, INIT_EXPR,
4937 DECL_SOURCE_LOCATION (arg), arg,
4938 DECL_ARG_TYPE (arg));
4939 else if (type_build_ctor_call (parm.frame_type))
4940 {
4941 vec<tree, va_gc> *p_in;
4942 if (CLASS_TYPE_P (parm.frame_type)
4943 && classtype_has_non_deleted_move_ctor (parm.frame_type))
4944 p_in = make_tree_vector_single (move (arg));
4945 else if (lvalue_p (arg))
4946 p_in = make_tree_vector_single (rvalue (arg));
4947 else
4948 p_in = make_tree_vector_single (arg);
4949 /* Construct in place or move as relevant. */
4950 r = build_special_member_call (fld_idx, complete_ctor_identifier,
4951 &p_in, parm.frame_type,
4952 LOOKUP_NORMAL,
4953 tf_warning_or_error);
4954 release_tree_vector (p_in);
4955 }
4956 else
4957 {
4958 if (!same_type_p (parm.frame_type, DECL_ARG_TYPE (arg)))
4959 r = build1_loc (DECL_SOURCE_LOCATION (arg), CONVERT_EXPR,
4960 parm.frame_type, arg);
4961 else
4962 r = arg;
4963 r = build_modify_expr (fn_start, fld_idx, parm.frame_type,
4964 INIT_EXPR, DECL_SOURCE_LOCATION (arg), r,
4965 TREE_TYPE (r));
4966 }
4967 finish_expr_stmt (r);
4968 if (!parm.trivial_dtor)
4969 {
4970 if (param_dtor_list == NULL)
4971 param_dtor_list = make_tree_vector ();
4972 vec_safe_push (param_dtor_list, parm.field_id);
4973 /* Cleanup this frame copy on exception. */
4974 parm.fr_copy_dtor
4975 = build_special_member_call (fld_idx, complete_dtor_identifier,
4976 NULL, parm.frame_type,
4977 LOOKUP_NORMAL,
4978 tf_warning_or_error);
4979 /* This var is now live. */
4980 r = build_modify_expr (fn_start, parm.guard_var,
4981 boolean_type_node, INIT_EXPR, fn_start,
4982 boolean_true_node, boolean_type_node);
4983 finish_expr_stmt (r);
4984 }
4985 }
4986 }
4987
4988 /* Set up the promise. */
4989 tree promise_m
4990 = lookup_member (coro_frame_type, promise_name,
4991 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
4992
4993 tree p = build_class_member_access_expr (deref_fp, promise_m, NULL_TREE,
4994 false, tf_warning_or_error);
4995
4996 tree promise_dtor = NULL_TREE;
4997 if (type_build_ctor_call (promise_type))
4998 {
4999 /* Do a placement new constructor for the promise type (we never call
5000 the new operator, just the constructor on the object in place in the
5001 frame).
5002
5003 First try to find a constructor with the same parameter list as the
5004 original function (if it has params), failing that find a constructor
5005 with no parameter list. */
5006
5007 if (DECL_ARGUMENTS (orig))
5008 {
5009 r = build_special_member_call (p, complete_ctor_identifier,
5010 &promise_args, promise_type,
5011 LOOKUP_NORMAL, tf_none);
5012 release_tree_vector (promise_args);
5013 }
5014 else
5015 r = NULL_TREE;
5016
5017 if (r == NULL_TREE || r == error_mark_node)
5018 r = build_special_member_call (p, complete_ctor_identifier, NULL,
5019 promise_type, LOOKUP_NORMAL,
5020 tf_warning_or_error);
5021
5022 r = coro_build_cvt_void_expr_stmt (r, fn_start);
5023 finish_expr_stmt (r);
5024
5025 r = build_modify_expr (fn_start, coro_promise_live, boolean_type_node,
5026 INIT_EXPR, fn_start, boolean_true_node,
5027 boolean_type_node);
5028 finish_expr_stmt (r);
5029
5030 promise_dtor
5031 = build_special_member_call (p, complete_dtor_identifier,
5032 NULL, promise_type, LOOKUP_NORMAL,
5033 tf_warning_or_error);
5034 }
5035
5036 /* Set up a new bind context for the GRO. */
5037 tree gro_context_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
5038 /* Make and connect the scope blocks. */
5039 tree gro_block = make_node (BLOCK);
5040 BLOCK_SUPERCONTEXT (gro_block) = top_block;
5041 BLOCK_SUBBLOCKS (top_block) = gro_block;
5042 BIND_EXPR_BLOCK (gro_context_bind) = gro_block;
5043 add_stmt (gro_context_bind);
5044
5045 tree get_ro
5046 = coro_build_promise_expression (orig, p,
5047 coro_get_return_object_identifier,
5048 fn_start, NULL, /*musthave=*/true);
5049 /* Without a return object we haven't got much clue what's going on. */
5050 if (get_ro == error_mark_node)
5051 {
5052 BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body);
5053 DECL_SAVED_TREE (orig) = newbody;
5054 /* Suppress warnings about the missing return value. */
5055 TREE_NO_WARNING (orig) = true;
5056 return false;
5057 }
5058
5059 tree gro_context_body = push_stmt_list ();
5060 tree gro_type = TREE_TYPE (get_ro);
5061 bool gro_is_void_p = VOID_TYPE_P (gro_type);
5062
5063 tree gro = NULL_TREE;
5064 tree gro_bind_vars = NULL_TREE;
5065 /* Used for return objects in the RESULT slot. */
5066 tree gro_ret_dtor = NULL_TREE;
5067 tree gro_cleanup_stmt = NULL_TREE;
5068 /* We have to sequence the call to get_return_object before initial
5069 suspend. */
5070 if (gro_is_void_p)
5071 r = get_ro;
5072 else if (same_type_p (gro_type, fn_return_type))
5073 {
5074 /* [dcl.fct.def.coroutine] / 7
5075 The expression promise.get_return_object() is used to initialize the
5076 glvalue result or... (see below)
5077 Construct the return result directly. */
5078 if (type_build_ctor_call (gro_type))
5079 {
5080 vec<tree, va_gc> *arg = make_tree_vector_single (get_ro);
5081 r = build_special_member_call (DECL_RESULT (orig),
5082 complete_ctor_identifier,
5083 &arg, gro_type, LOOKUP_NORMAL,
5084 tf_warning_or_error);
5085 release_tree_vector (arg);
5086 }
5087 else
5088 r = build2_loc (fn_start, INIT_EXPR, gro_type,
5089 DECL_RESULT (orig), get_ro);
5090
5091 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type))
5092 /* If some part of the initalization code (prior to the await_resume
5093 of the initial suspend expression), then we need to clean up the
5094 return value. */
5095 gro_ret_dtor
5096 = build_special_member_call (DECL_RESULT (orig),
5097 complete_dtor_identifier, NULL,
5098 gro_type, LOOKUP_NORMAL,
5099 tf_warning_or_error);
5100 }
5101 else
5102 {
5103 /* ... or ... Construct an object that will be used as the single
5104 param to the CTOR for the return object. */
5105 gro = build_lang_decl (VAR_DECL, get_identifier ("coro.gro"), gro_type);
5106 DECL_CONTEXT (gro) = current_scope ();
5107 DECL_ARTIFICIAL (gro) = true;
5108 DECL_IGNORED_P (gro) = true;
5109 add_decl_expr (gro);
5110 gro_bind_vars = gro;
5111 if (type_build_ctor_call (gro_type))
5112 {
5113 vec<tree, va_gc> *arg = make_tree_vector_single (get_ro);
5114 r = build_special_member_call (gro, complete_ctor_identifier,
5115 &arg, gro_type, LOOKUP_NORMAL,
5116 tf_warning_or_error);
5117 release_tree_vector (arg);
5118 }
5119 else
5120 r = build2_loc (fn_start, INIT_EXPR, gro_type, gro, get_ro);
5121 /* The constructed object might require a cleanup. */
5122 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type))
5123 {
5124 gro_cleanup_stmt
5125 = build_special_member_call (gro, complete_dtor_identifier,
5126 NULL, gro_type, LOOKUP_NORMAL,
5127 tf_warning_or_error);
5128 gro_cleanup_stmt = build_stmt (input_location, CLEANUP_STMT, NULL,
5129 gro_cleanup_stmt, gro);
5130 }
5131 }
5132 finish_expr_stmt (r);
5133
5134 if (gro_cleanup_stmt && gro_cleanup_stmt != error_mark_node)
5135 CLEANUP_BODY (gro_cleanup_stmt) = push_stmt_list ();
5136
5137 /* If we have a live g.r.o in the return slot, then signal this for exception
5138 cleanup. */
5139 if (gro_ret_dtor)
5140 {
5141 r = build_modify_expr (fn_start, coro_gro_live, boolean_type_node,
5142 INIT_EXPR, fn_start, boolean_true_node,
5143 boolean_type_node);
5144 finish_expr_stmt (r);
5145 }
5146 /* Initialize the resume_idx_name to 0, meaning "not started". */
5147 tree resume_idx_m
5148 = lookup_member (coro_frame_type, resume_idx_name,
5149 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
5150 tree resume_idx
5151 = build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false,
5152 tf_warning_or_error);
5153 r = build_int_cst (short_unsigned_type_node, 0);
5154 r = build2_loc (fn_start, INIT_EXPR, short_unsigned_type_node, resume_idx, r);
5155 r = coro_build_cvt_void_expr_stmt (r, fn_start);
5156 add_stmt (r);
5157
5158 /* So .. call the actor .. */
5159 r = build_call_expr_loc (fn_start, actor, 1, coro_fp);
5160 r = maybe_cleanup_point_expr_void (r);
5161 add_stmt (r);
5162
5163 /* Switch to using 'input_location' as the loc, since we're now more
5164 logically doing things related to the end of the function. */
5165
5166 /* The ramp is done, we just need the return value.
5167 [dcl.fct.def.coroutine] / 7
5168 The expression promise.get_return_object() is used to initialize the
5169 glvalue result or prvalue result object of a call to a coroutine.
5170
5171 If the 'get return object' is non-void, then we built it before the
5172 promise was constructed. We now supply a reference to that var,
5173 either as the return value (if it's the same type) or to the CTOR
5174 for an object of the return type. */
5175
5176 if (same_type_p (gro_type, fn_return_type))
5177 r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig);
5178 else
5179 {
5180 if (CLASS_TYPE_P (fn_return_type))
5181 {
5182 /* For class type return objects, we can attempt to construct,
5183 even if the gro is void. */
5184 vec<tree, va_gc> *args = NULL;
5185 vec<tree, va_gc> **arglist = NULL;
5186 if (!gro_is_void_p)
5187 {
5188 args = make_tree_vector_single (rvalue (gro));
5189 arglist = &args;
5190 }
5191 r = build_special_member_call (NULL_TREE,
5192 complete_ctor_identifier, arglist,
5193 fn_return_type, LOOKUP_NORMAL,
5194 tf_warning_or_error);
5195 r = build_cplus_new (fn_return_type, r, tf_warning_or_error);
5196 if (args)
5197 release_tree_vector (args);
5198 }
5199 else if (gro_is_void_p)
5200 {
5201 /* We can't initialize a non-class return value from void. */
5202 error_at (input_location, "cannot initialize a return object of type"
5203 " %qT with an rvalue of type %<void%>", fn_return_type);
5204 r = error_mark_node;
5205 }
5206 else
5207 r = build1_loc (input_location, CONVERT_EXPR,
5208 fn_return_type, rvalue (gro));
5209 }
5210
5211 finish_return_stmt (r);
5212
5213 if (gro_cleanup_stmt)
5214 {
5215 CLEANUP_BODY (gro_cleanup_stmt)
5216 = pop_stmt_list (CLEANUP_BODY (gro_cleanup_stmt));
5217 add_stmt (gro_cleanup_stmt);
5218 }
5219
5220 /* Finish up the ramp function. */
5221 BIND_EXPR_VARS (gro_context_bind) = gro_bind_vars;
5222 BIND_EXPR_BODY (gro_context_bind) = pop_stmt_list (gro_context_body);
5223 TREE_SIDE_EFFECTS (gro_context_bind) = true;
5224
5225 if (flag_exceptions)
5226 {
5227 TRY_HANDLERS (ramp_cleanup) = push_stmt_list ();
5228 tree handler = begin_handler ();
5229 finish_handler_parms (NULL_TREE, handler); /* catch (...) */
5230
5231 /* If we have a live G.R.O in the return slot, then run its DTOR.
5232 When the return object is constructed from a separate g.r.o, this is
5233 already handled by its regular cleanup. */
5234 if (gro_ret_dtor && gro_ret_dtor != error_mark_node)
5235 {
5236 tree gro_d_if = begin_if_stmt ();
5237 finish_if_stmt_cond (coro_gro_live, gro_d_if);
5238 finish_expr_stmt (gro_ret_dtor);
5239 finish_then_clause (gro_d_if);
5240 tree gro_d_if_scope = IF_SCOPE (gro_d_if);
5241 IF_SCOPE (gro_d_if) = NULL;
5242 gro_d_if = do_poplevel (gro_d_if_scope);
5243 add_stmt (gro_d_if);
5244 }
5245
5246 /* If the promise is live, then run its dtor if that's available. */
5247 if (promise_dtor && promise_dtor != error_mark_node)
5248 {
5249 tree promise_d_if = begin_if_stmt ();
5250 finish_if_stmt_cond (coro_promise_live, promise_d_if);
5251 finish_expr_stmt (promise_dtor);
5252 finish_then_clause (promise_d_if);
5253 tree promise_d_if_scope = IF_SCOPE (promise_d_if);
5254 IF_SCOPE (promise_d_if) = NULL;
5255 promise_d_if = do_poplevel (promise_d_if_scope);
5256 add_stmt (promise_d_if);
5257 }
5258
5259 /* Clean up any frame copies of parms with non-trivial dtors. */
5260 if (DECL_ARGUMENTS (orig))
5261 for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
5262 arg = DECL_CHAIN (arg))
5263 {
5264 param_info *parm_i = param_uses->get (arg);
5265 if (parm_i->trivial_dtor)
5266 continue;
5267 if (parm_i->fr_copy_dtor && parm_i->fr_copy_dtor != error_mark_node)
5268 {
5269 tree dtor_if = begin_if_stmt ();
5270 finish_if_stmt_cond (parm_i->guard_var, dtor_if);
5271 finish_expr_stmt (parm_i->fr_copy_dtor);
5272 finish_then_clause (dtor_if);
5273 tree parm_d_if_scope = IF_SCOPE (dtor_if);
5274 IF_SCOPE (dtor_if) = NULL;
5275 dtor_if = do_poplevel (parm_d_if_scope);
5276 add_stmt (dtor_if);
5277 }
5278 }
5279
5280 /* We always expect to delete the frame. */
5281 tree del_coro_fr = coro_get_frame_dtor (coro_fp, orig, frame_size,
5282 promise_type, fn_start);
5283 finish_expr_stmt (del_coro_fr);
5284 tree rethrow = build_throw (fn_start, NULL_TREE);
5285 TREE_NO_WARNING (rethrow) = true;
5286 finish_expr_stmt (rethrow);
5287 finish_handler (handler);
5288 TRY_HANDLERS (ramp_cleanup) = pop_stmt_list (TRY_HANDLERS (ramp_cleanup));
5289 }
5290
5291 BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body);
5292 TREE_SIDE_EFFECTS (ramp_bind) = true;
5293
5294 /* Start to build the final functions.
5295
5296 We push_deferring_access_checks to avoid these routines being seen as
5297 nested by the middle end; we are doing the outlining here. */
5298
5299 push_deferring_access_checks (dk_no_check);
5300
5301 /* Build the actor... */
5302 build_actor_fn (fn_start, coro_frame_type, actor, fnbody, orig, param_uses,
5303 &local_var_uses, param_dtor_list, resume_fn_field,
5304 resume_idx_field, body_aw_points.await_number, frame_size);
5305
5306 /* Destroyer ... */
5307 build_destroy_fn (fn_start, coro_frame_type, destroy, actor);
5308
5309 pop_deferring_access_checks ();
5310
5311 DECL_SAVED_TREE (orig) = newbody;
5312 /* Link our new functions into the list. */
5313 TREE_CHAIN (destroy) = TREE_CHAIN (orig);
5314 TREE_CHAIN (actor) = destroy;
5315 TREE_CHAIN (orig) = actor;
5316
5317 *resumer = actor;
5318 *destroyer = destroy;
5319
5320 delete suspend_points;
5321 suspend_points = NULL;
5322 return true;
5323 }
5324
5325 #include "gt-cp-coroutines.h"
5326
5327