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