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