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