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