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