Bug Summary

File:build/gcc/cp/coroutines.cc
Warning:line 1363, column 8
Value stored to 'co_ret_call' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-suse-linux -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name coroutines.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -resource-dir /usr/lib64/clang/15.0.7 -D IN_GCC_FRONTEND -D IN_GCC -D HAVE_CONFIG_H -I . -I cp -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/x86_64-suse-linux -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/backward -internal-isystem /usr/lib64/clang/15.0.7/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../x86_64-suse-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-narrowing -Wwrite-strings -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fdeprecated-macro -fdebug-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=plist-html -analyzer-config silence-checkers=core.NullDereference -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2023-03-27-141847-20772-1/report-w1st5W.plist -x c++ /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc
1/* coroutine-specific state, expansions and tests.
2
3 Copyright (C) 2018-2023 Free Software Foundation, Inc.
4
5 Contributed by Iain Sandoe <iain@sandoe.co.uk> under contract to Facebook.
6
7This file is part of GCC.
8
9GCC is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
11Software Foundation; either version 3, or (at your option) any later
12version.
13
14GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
18
19You should have received a copy of the GNU General Public License
20along 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
36static 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
82struct 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
102struct 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
114static GTY (()) hash_table<coroutine_info_hasher> *coroutine_info_table;
115
116/* We will initialize state lazily. */
117static 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
124hashval_t
125coroutine_info_hasher::hash (coroutine_info *info)
126{
127 return DECL_UID (info->function_decl)((contains_struct_check ((info->function_decl), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 127, __FUNCTION__))->decl_minimal.uid)
;
128}
129
130/* Return a hash value for the compare value COMP. */
131
132hashval_t
133coroutine_info_hasher::hash (const compare_type& comp)
134{
135 return DECL_UID (comp)((contains_struct_check ((comp), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 135, __FUNCTION__))->decl_minimal.uid)
;
136}
137
138/* Return true if the entries pointed to by LHS and RHS are for the
139 same coroutine. */
140
141bool
142coroutine_info_hasher::equal (coroutine_info *lhs, coroutine_info *rhs)
143{
144 return lhs->function_decl == rhs->function_decl;
145}
146
147bool
148coroutine_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
156coroutine_info *
157get_or_insert_coroutine_info (tree fn_decl)
158{
159 gcc_checking_assert (coroutine_info_table != NULL)((void)(!(coroutine_info_table != nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 159, __FUNCTION__), 0 : 0))
;
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 == NULLnullptr)
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
175coroutine_info *
176get_coroutine_info (tree fn_decl)
177{
178 if (coroutine_info_table == NULLnullptr)
179 return NULLnullptr;
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 NULLnullptr;
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
193static GTY(()) tree coro_traits_identifier;
194static GTY(()) tree coro_handle_identifier;
195static GTY(()) tree coro_promise_type_identifier;
196
197/* Required promise method name identifiers. */
198
199static GTY(()) tree coro_await_transform_identifier;
200static GTY(()) tree coro_initial_suspend_identifier;
201static GTY(()) tree coro_final_suspend_identifier;
202static GTY(()) tree coro_return_void_identifier;
203static GTY(()) tree coro_return_value_identifier;
204static GTY(()) tree coro_yield_value_identifier;
205static GTY(()) tree coro_resume_identifier;
206static GTY(()) tree coro_address_identifier;
207static GTY(()) tree coro_from_address_identifier;
208static GTY(()) tree coro_get_return_object_identifier;
209static GTY(()) tree coro_gro_on_allocation_fail_identifier;
210static GTY(()) tree coro_unhandled_exception_identifier;
211
212/* Awaitable methods. */
213
214static GTY(()) tree coro_await_ready_identifier;
215static GTY(()) tree coro_await_suspend_identifier;
216static GTY(()) tree coro_await_resume_identifier;
217
218/* Accessors for the coroutine frame state used by the implementation. */
219
220static GTY(()) tree coro_resume_fn_id;
221static GTY(()) tree coro_destroy_fn_id;
222static GTY(()) tree coro_promise_id;
223static GTY(()) tree coro_frame_needs_free_id;
224static GTY(()) tree coro_resume_index_id;
225static GTY(()) tree coro_self_handle_id;
226static GTY(()) tree coro_actor_continue_id;
227static 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
232static void
233coro_init_identifiers ()
234{
235 coro_traits_identifier = get_identifier ("coroutine_traits")(__builtin_constant_p ("coroutine_traits") ? get_identifier_with_length
(("coroutine_traits"), strlen ("coroutine_traits")) : get_identifier
("coroutine_traits"))
;
236 coro_handle_identifier = get_identifier ("coroutine_handle")(__builtin_constant_p ("coroutine_handle") ? get_identifier_with_length
(("coroutine_handle"), strlen ("coroutine_handle")) : get_identifier
("coroutine_handle"))
;
237 coro_promise_type_identifier = get_identifier ("promise_type")(__builtin_constant_p ("promise_type") ? get_identifier_with_length
(("promise_type"), strlen ("promise_type")) : get_identifier
("promise_type"))
;
238
239 coro_await_transform_identifier = get_identifier ("await_transform")(__builtin_constant_p ("await_transform") ? get_identifier_with_length
(("await_transform"), strlen ("await_transform")) : get_identifier
("await_transform"))
;
240 coro_initial_suspend_identifier = get_identifier ("initial_suspend")(__builtin_constant_p ("initial_suspend") ? get_identifier_with_length
(("initial_suspend"), strlen ("initial_suspend")) : get_identifier
("initial_suspend"))
;
241 coro_final_suspend_identifier = get_identifier ("final_suspend")(__builtin_constant_p ("final_suspend") ? get_identifier_with_length
(("final_suspend"), strlen ("final_suspend")) : get_identifier
("final_suspend"))
;
242 coro_return_void_identifier = get_identifier ("return_void")(__builtin_constant_p ("return_void") ? get_identifier_with_length
(("return_void"), strlen ("return_void")) : get_identifier (
"return_void"))
;
243 coro_return_value_identifier = get_identifier ("return_value")(__builtin_constant_p ("return_value") ? get_identifier_with_length
(("return_value"), strlen ("return_value")) : get_identifier
("return_value"))
;
244 coro_yield_value_identifier = get_identifier ("yield_value")(__builtin_constant_p ("yield_value") ? get_identifier_with_length
(("yield_value"), strlen ("yield_value")) : get_identifier (
"yield_value"))
;
245 coro_resume_identifier = get_identifier ("resume")(__builtin_constant_p ("resume") ? get_identifier_with_length
(("resume"), strlen ("resume")) : get_identifier ("resume"))
;
246 coro_address_identifier = get_identifier ("address")(__builtin_constant_p ("address") ? get_identifier_with_length
(("address"), strlen ("address")) : get_identifier ("address"
))
;
247 coro_from_address_identifier = get_identifier ("from_address")(__builtin_constant_p ("from_address") ? get_identifier_with_length
(("from_address"), strlen ("from_address")) : get_identifier
("from_address"))
;
248 coro_get_return_object_identifier = get_identifier ("get_return_object")(__builtin_constant_p ("get_return_object") ? get_identifier_with_length
(("get_return_object"), strlen ("get_return_object")) : get_identifier
("get_return_object"))
;
249 coro_gro_on_allocation_fail_identifier =
250 get_identifier ("get_return_object_on_allocation_failure")(__builtin_constant_p ("get_return_object_on_allocation_failure"
) ? get_identifier_with_length (("get_return_object_on_allocation_failure"
), strlen ("get_return_object_on_allocation_failure")) : get_identifier
("get_return_object_on_allocation_failure"))
;
251 coro_unhandled_exception_identifier = get_identifier ("unhandled_exception")(__builtin_constant_p ("unhandled_exception") ? get_identifier_with_length
(("unhandled_exception"), strlen ("unhandled_exception")) : get_identifier
("unhandled_exception"))
;
252
253 coro_await_ready_identifier = get_identifier ("await_ready")(__builtin_constant_p ("await_ready") ? get_identifier_with_length
(("await_ready"), strlen ("await_ready")) : get_identifier (
"await_ready"))
;
254 coro_await_suspend_identifier = get_identifier ("await_suspend")(__builtin_constant_p ("await_suspend") ? get_identifier_with_length
(("await_suspend"), strlen ("await_suspend")) : get_identifier
("await_suspend"))
;
255 coro_await_resume_identifier = get_identifier ("await_resume")(__builtin_constant_p ("await_resume") ? get_identifier_with_length
(("await_resume"), strlen ("await_resume")) : get_identifier
("await_resume"))
;
256
257 /* Coroutine state frame field accessors. */
258 coro_resume_fn_id = get_identifier ("_Coro_resume_fn")(__builtin_constant_p ("_Coro_resume_fn") ? get_identifier_with_length
(("_Coro_resume_fn"), strlen ("_Coro_resume_fn")) : get_identifier
("_Coro_resume_fn"))
;
259 coro_destroy_fn_id = get_identifier ("_Coro_destroy_fn")(__builtin_constant_p ("_Coro_destroy_fn") ? get_identifier_with_length
(("_Coro_destroy_fn"), strlen ("_Coro_destroy_fn")) : get_identifier
("_Coro_destroy_fn"))
;
260 coro_promise_id = get_identifier ("_Coro_promise")(__builtin_constant_p ("_Coro_promise") ? get_identifier_with_length
(("_Coro_promise"), strlen ("_Coro_promise")) : get_identifier
("_Coro_promise"))
;
261 coro_frame_needs_free_id = get_identifier ("_Coro_frame_needs_free")(__builtin_constant_p ("_Coro_frame_needs_free") ? get_identifier_with_length
(("_Coro_frame_needs_free"), strlen ("_Coro_frame_needs_free"
)) : get_identifier ("_Coro_frame_needs_free"))
;
262 coro_frame_i_a_r_c_id = get_identifier ("_Coro_initial_await_resume_called")(__builtin_constant_p ("_Coro_initial_await_resume_called") ?
get_identifier_with_length (("_Coro_initial_await_resume_called"
), strlen ("_Coro_initial_await_resume_called")) : get_identifier
("_Coro_initial_await_resume_called"))
;
263 coro_resume_index_id = get_identifier ("_Coro_resume_index")(__builtin_constant_p ("_Coro_resume_index") ? get_identifier_with_length
(("_Coro_resume_index"), strlen ("_Coro_resume_index")) : get_identifier
("_Coro_resume_index"))
;
264 coro_self_handle_id = get_identifier ("_Coro_self_handle")(__builtin_constant_p ("_Coro_self_handle") ? get_identifier_with_length
(("_Coro_self_handle"), strlen ("_Coro_self_handle")) : get_identifier
("_Coro_self_handle"))
;
265 coro_actor_continue_id = get_identifier ("_Coro_actor_continue")(__builtin_constant_p ("_Coro_actor_continue") ? get_identifier_with_length
(("_Coro_actor_continue"), strlen ("_Coro_actor_continue")) :
get_identifier ("_Coro_actor_continue"))
;
266}
267
268/* Trees we only need to set up once. */
269
270static GTY(()) tree coro_traits_templ;
271static GTY(()) tree coro_handle_templ;
272static 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
286static tree
287find_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_nodecp_global_trees[CPTI_STD], coro_traits_identifier,
295 LOOK_want::NORMAL,
296 /*complain=*/!traits_error_emitted);
297 if (traits_decl == error_mark_nodeglobal_trees[TI_ERROR_MARK]
298 || !DECL_TYPE_TEMPLATE_P (traits_decl)(((enum tree_code) (traits_decl)->base.code) == TEMPLATE_DECL
&& ((struct tree_template_decl *)(const_cast<union
tree_node *> ((((tree_check ((traits_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 298, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((traits_decl
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 298, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->base
.code) == TYPE_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_nodecp_global_trees[CPTI_STD], coro_traits_identifier);
305 inform (&richloc, "perhaps %<#include <coroutine>%> is missing");
306 traits_error_emitted = true;
307 }
308 return NULL_TREE(tree) nullptr;
309 }
310 else
311 return traits_decl;
312}
313
314/* Instantiate Coroutine traits for the function signature. */
315
316static tree
317instantiate_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)((contains_struct_check ((fndecl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 324, __FUNCTION__))->typed.type)
;
325 tree arg = DECL_ARGUMENTS (fndecl)((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 325, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
;
326 tree arg_node = TYPE_ARG_TYPES (functyp)((tree_check2 ((functyp), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 326, __FUNCTION__, (FUNCTION_TYPE), (METHOD_TYPE)))->type_non_common
.values)
;
327 tree argtypes = make_tree_vec (list_length (arg_node)-1);
328 unsigned p = 0;
329
330 while (arg_node != NULL_TREE(tree) nullptr && !VOID_TYPE_P (TREE_VALUE (arg_node))(((enum tree_code) (((tree_check ((arg_node), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 330, __FUNCTION__, (TREE_LIST)))->list.value))->base.
code) == VOID_TYPE)
)
331 {
332 if (is_this_parameter (arg)
333 || DECL_NAME (arg)((contains_struct_check ((arg), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 333, __FUNCTION__))->decl_minimal.name)
== closure_identifiercp_global_trees[CPTI_CLOSURE_IDENTIFIER])
334 {
335 /* We pass a reference to *this to the param preview. */
336 tree ct = TREE_TYPE (TREE_TYPE (arg))((contains_struct_check ((((contains_struct_check ((arg), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 336, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 336, __FUNCTION__))->typed.type)
;
337 TREE_VEC_ELT (argtypes, p++)(*((const_cast<tree *> (tree_vec_elt_check ((argtypes),
(p++), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 337, __FUNCTION__)))))
= cp_build_reference_type (ct, false);
338 }
339 else
340 TREE_VEC_ELT (argtypes, p++)(*((const_cast<tree *> (tree_vec_elt_check ((argtypes),
(p++), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 340, __FUNCTION__)))))
= TREE_VALUE (arg_node)((tree_check ((arg_node), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 340, __FUNCTION__, (TREE_LIST)))->list.value)
;
341
342 arg_node = TREE_CHAIN (arg_node)((contains_struct_check ((arg_node), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 342, __FUNCTION__))->common.chain)
;
343 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 343, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 343, __FUNCTION__))->common.chain))
;
344 }
345
346 tree argtypepack = cxx_make_type (TYPE_ARGUMENT_PACK);
347 ARGUMENT_PACK_ARGS (argtypepack)(((enum tree_code) ((tree_check2 ((argtypepack), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 347, __FUNCTION__, (TYPE_ARGUMENT_PACK), (NONTYPE_ARGUMENT_PACK
))))->base.code) == TYPE_ARGUMENT_PACK ? ((contains_struct_check
((argtypepack), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 347, __FUNCTION__))->typed.type) : (*((const_cast<tree
*> (tree_operand_check ((argtypepack), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 347, __FUNCTION__))))))
= argtypes;
348
349 tree targ = make_tree_vec (2);
350 TREE_VEC_ELT (targ, 0)(*((const_cast<tree *> (tree_vec_elt_check ((targ), (0)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 350, __FUNCTION__)))))
= TREE_TYPE (functyp)((contains_struct_check ((functyp), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 350, __FUNCTION__))->typed.type)
;
351 TREE_VEC_ELT (targ, 1)(*((const_cast<tree *> (tree_vec_elt_check ((targ), (1)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 351, __FUNCTION__)))))
= argtypepack;
352
353 tree traits_class
354 = lookup_template_class (coro_traits_templ, targ,
355 /*in_decl=*/NULL_TREE(tree) nullptr, /*context=*/NULL_TREE(tree) nullptr,
356 /*entering scope=*/false, tf_warning_or_error);
357
358 if (traits_class == error_mark_nodeglobal_trees[TI_ERROR_MARK])
359 {
360 error_at (kw, "cannot instantiate %<coroutine traits%>");
361 return NULL_TREE(tree) nullptr;
362 }
363
364 return traits_class;
365}
366
367/* [coroutine.handle] */
368
369static tree
370find_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_nodecp_global_trees[CPTI_STD], coro_handle_identifier,
376 LOOK_want::NORMAL,
377 !coro_handle_error_emitted);
378 if (handle_decl == error_mark_nodeglobal_trees[TI_ERROR_MARK]
379 || !DECL_CLASS_TEMPLATE_P (handle_decl)((((enum tree_code) (handle_decl)->base.code) == TEMPLATE_DECL
&& ((struct tree_template_decl *)(const_cast<union
tree_node *> ((((tree_check ((handle_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 379, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((handle_decl
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 379, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->base
.code) == TYPE_DECL) && (((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((handle_decl
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 379, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->base
.code) == TYPE_DECL && ((contains_struct_check ((((struct
tree_template_decl *)(const_cast<union tree_node *> ((
((tree_check ((handle_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 379, __FUNCTION__, (TEMPLATE_DECL))))))))->result), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 379, __FUNCTION__))->decl_common.lang_flag_2)))
)
380 {
381 if (!coro_handle_error_emitted)
382 error_at (kw, "coroutines require a handle class template;"
383 " cannot find %<%E::%E%>", std_nodecp_global_trees[CPTI_STD], coro_handle_identifier);
384 coro_handle_error_emitted = true;
385 return NULL_TREE(tree) nullptr;
386 }
387 else
388 return handle_decl;
389}
390
391/* Instantiate the handle template for a given promise type. */
392
393static tree
394instantiate_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)(*((const_cast<tree *> (tree_vec_elt_check ((targ), (0)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 398, __FUNCTION__)))))
= promise_type;
399 tree handle_type
400 = lookup_template_class (coro_handle_identifier, targ,
401 /* in_decl=*/NULL_TREE(tree) nullptr,
402 /* context=*/std_nodecp_global_trees[CPTI_STD],
403 /* entering scope=*/false, tf_warning_or_error);
404
405 if (handle_type == error_mark_nodeglobal_trees[TI_ERROR_MARK])
406 {
407 error_at (kw, "cannot instantiate a %<coroutine handle%> for"
408 " promise type %qT", promise_type);
409 return NULL_TREE(tree) nullptr;
410 }
411
412 return handle_type;
413}
414
415/* Look for the promise_type in the instantiated traits. */
416
417static tree
418find_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)((contains_struct_check ((promise_type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 426, __FUNCTION__))->typed.type)
, promise_type);
427
428 /* NULL_TREE on fail. */
429 return promise_type;
430}
431
432static bool
433coro_promise_type_found_p (tree fndecl, location_t loc)
434{
435 gcc_assert (fndecl != NULL_TREE)((void)(!(fndecl != (tree) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 435, __FUNCTION__), 0 : 0))
;
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(tree) nullptr)
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(tree) nullptr)
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(tree) nullptr);
456 if (void_coro_handle_type == NULL_TREE(tree) nullptr)
457 return false;
458
459 /* A table to hold the state, per coroutine decl. */
460 gcc_checking_assert (coroutine_info_table == NULL)((void)(!(coroutine_info_table == nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 460, __FUNCTION__), 0 : 0))
;
461 coroutine_info_table =
462 hash_table<coroutine_info_hasher>::create_ggc (11);
463
464 if (coroutine_info_table == NULLnullptr)
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)((void)(!(coro_info) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 475, __FUNCTION__), 0 : 0))
;
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(tree) nullptr)
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(tree) nullptr)
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)((contains_struct_check ((fndecl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 509, __FUNCTION__))->decl_minimal.locus)
;
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))((contains_struct_check (((((struct tree_baselink*) (tree_check
((has_ret_void), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 514, __FUNCTION__, (BASELINK))))->functions)), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 514, __FUNCTION__))->decl_minimal.locus)
,
515 "%<return_void%> declared here");
516 has_ret_val = BASELINK_FUNCTIONS (has_ret_val)(((struct tree_baselink*) (tree_check ((has_ret_val), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 516, __FUNCTION__, (BASELINK))))->functions)
;
517 const char *message = "%<return_value%> declared here";
518 if (TREE_CODE (has_ret_val)((enum tree_code) (has_ret_val)->base.code) == OVERLOAD)
519 {
520 has_ret_val = OVL_FIRST (has_ret_val)ovl_first (has_ret_val);
521 message = "%<return_value%> first declared here";
522 }
523 inform (DECL_SOURCE_LOCATION (has_ret_val)((contains_struct_check ((has_ret_val), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 523, __FUNCTION__))->decl_minimal.locus)
, 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(tree) nullptr)
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. */
560static GTY(()) hash_map<tree, tree> *to_ramp;
561
562/* Given a tree that is an actor or destroy, find the ramp function. */
563
564tree
565coro_get_ramp_function (tree decl)
566{
567 if (!to_ramp)
568 return NULL_TREE(tree) nullptr;
569 tree *p = to_ramp->get (decl);
570 if (p)
571 return *p;
572 return NULL_TREE(tree) nullptr;
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
578tree
579coro_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(tree) nullptr;
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
590tree
591coro_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(tree) nullptr;
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
602static tree
603get_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(tree) nullptr;
609}
610
611static tree
612get_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(tree) nullptr;
618}
619
620static tree
621get_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(tree) nullptr;
627}
628
629static tree
630get_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(tree) nullptr;
636}
637
638static tree
639lookup_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(tree) nullptr)
647 {
648 error_at (loc, "no member named %qE in %qT", member_id, promise);
649 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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
660static tree
661coro_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_nodeglobal_trees[TI_ERROR_MARK])
667 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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(tree) nullptr;
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)(((enum tree_code) (meth)->base.code) == BASELINK))
678 expr = build_new_method_call (promise, meth, args, NULL_TREE(tree) nullptr,
679 LOOKUP_NORMAL((1 << 0)), NULLnullptr, tf_warning_or_error);
680 else
681 {
682 expr = build_class_member_access_expr (promise, meth, NULL_TREE(tree) nullptr,
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
696static tree
697get_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, NULLnullptr,
705 coro_return_void_identifier,
706 loc, NULLnullptr, musthave);
707 /* Don't return an error if it's an optional call. */
708 if (!musthave && info->return_void == error_mark_nodeglobal_trees[TI_ERROR_MARK])
709 return NULL_TREE(tree) nullptr;
710 return info->return_void;
711 }
712 return musthave ? error_mark_nodeglobal_trees[TI_ERROR_MARK] : NULL_TREE(tree) nullptr;
713}
714
715/* Lookup an Awaitable member, which should be await_ready, await_suspend
716 or await_resume. */
717
718static tree
719lookup_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(tree) nullptr)
725 {
726 error_at (loc, "no member named %qE in %qT", member_id, await_type);
727 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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
735static bool
736coro_common_keyword_context_valid_p (tree fndecl, location_t kw_loc,
737 const char *kw_name)
738{
739 if (fndecl == NULL_TREE(tree) nullptr)
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)((((((enum tree_code) (fndecl)->base.code) == FUNCTION_DECL
&& !(((enum tree_code) (fndecl)->base.code) == FUNCTION_DECL
&& ((contains_struct_check ((fndecl), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_common.lang_specific) &&
__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) (fndecl)->base.code) == TEMPLATE_DECL
? ((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__, (TEMPLATE_DECL))))))))->result : fndecl
)), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_common.lang_specific); if (!((
(enum tree_code) (fndecl)->base.code) == FUNCTION_DECL || (
((enum tree_code) (fndecl)->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((fndecl
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->base
.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__); &lt->u.fn; })->thunk_p)) &&
((((contains_struct_check ((fndecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_common.lang_specific) ? ((contains_struct_check
((fndecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_common.lang_specific)->u.base
.language : (((enum tree_code) (fndecl)->base.code) == FUNCTION_DECL
? lang_c : lang_cplusplus)) == lang_c)) && ((contains_struct_check
((fndecl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_minimal.name) != (tree) nullptr
&& ((tree_check ((((contains_struct_check ((fndecl),
(TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__))->decl_minimal.name)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 746, __FUNCTION__, (IDENTIFIER_NODE))) == global_trees[TI_MAIN_IDENTIFIER
])) && flag_hosted)
)
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)((contains_struct_check (((tree_check2 (((((enum tree_code) (
fndecl)->base.code) == TEMPLATE_DECL ? ((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((fndecl
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 754, __FUNCTION__, (TEMPLATE_DECL))))))))->result : fndecl
)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 754, __FUNCTION__, (VAR_DECL), (FUNCTION_DECL)))), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 754, __FUNCTION__))->decl_common.lang_flag_8)
)
755 {
756 cp_function_chain((cfun + 0)->language)->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)((tree_not_check2 (((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 766, __FUNCTION__, (FUNCTION_DECL)))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 766, __FUNCTION__, (TREE_VEC), (SSA_NAME)))->base.u.bits
.lang_flag_2)
)
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)((tree_check (((((enum tree_code) (fndecl)->base.code) == TEMPLATE_DECL
? ((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 786, __FUNCTION__, (TEMPLATE_DECL))))))))->result : fndecl
)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 786, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_constructor
)
)
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)((tree_check (((((enum tree_code) (fndecl)->base.code) == TEMPLATE_DECL
? ((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 793, __FUNCTION__, (TEMPLATE_DECL))))))))->result : fndecl
)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 793, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_destructor
)
)
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
805static bool
806coro_function_valid_p (tree fndecl)
807{
808 location_t f_loc = DECL_SOURCE_LOCATION (fndecl)((contains_struct_check ((fndecl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 808, __FUNCTION__))->decl_minimal.locus)
;
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(tree) nullptr
819 || get_coroutine_promise_type (fndecl) == NULL_TREE(tree) nullptr)
820 return false;
821
822 if (current_function_returns_value((cfun + 0)->language)->returns_value || current_function_returns_null((cfun + 0)->language)->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
835enum 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
847static tree
848get_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)(__builtin_constant_p (buf) ? get_identifier_with_length ((buf
), strlen (buf)) : get_identifier (buf))
;
860 free (buf);
861 ret = build_lang_decl (VAR_DECL, ret, v_type);
862 DECL_ARTIFICIAL (ret)((contains_struct_check ((ret), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 862, __FUNCTION__))->decl_common.artificial_flag)
= true;
863 return ret;
864}
865
866/* Helpers to diagnose missing noexcept on final await expressions. */
867
868static bool
869coro_diagnose_throwing_fn (tree fndecl)
870{
871 if (!TYPE_NOTHROW_P (TREE_TYPE (fndecl))nothrow_spec_p (((tree_class_check (((tree_check2 ((((contains_struct_check
((fndecl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 871, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 871, __FUNCTION__, (FUNCTION_TYPE), (METHOD_TYPE)))), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 871, __FUNCTION__))->type_non_common.lang_1))
)
872 {
873 location_t f_loc = cp_expr_loc_or_loc (fndecl,
874 DECL_SOURCE_LOCATION (fndecl)((contains_struct_check ((fndecl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 874, __FUNCTION__))->decl_minimal.locus)
);
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
883static bool
884coro_diagnose_throwing_final_aw_expr (tree expr)
885{
886 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == TARGET_EXPR)
887 expr = TARGET_EXPR_INITIAL (expr)(*(tree_operand_check_code ((expr), (TARGET_EXPR), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 887, __FUNCTION__)))
;
888 tree fn = NULL_TREE(tree) nullptr;
889 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CALL_EXPR)
890 fn = CALL_EXPR_FN (expr)(*((const_cast<tree*> (tree_operand_check (((tree_check
((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 890, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 890, __FUNCTION__)))))
;
891 else if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == AGGR_INIT_EXPR)
892 fn = AGGR_INIT_EXPR_FN (expr)(*((const_cast<tree*> (tree_operand_check (((tree_check
((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 892, __FUNCTION__, (AGGR_INIT_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 892, __FUNCTION__)))))
;
893 else if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CONSTRUCTOR)
894 return false;
895 else
896 {
897 gcc_checking_assert (0 && "unhandled expression type")((void)(!(0 && "unhandled expression type") ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 897, __FUNCTION__), 0 : 0))
;
898 return false;
899 }
900 fn = TREE_OPERAND (fn, 0)(*((const_cast<tree*> (tree_operand_check ((fn), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 900, __FUNCTION__)))))
;
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
914static tree
915build_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))((((enum tree_code) (((contains_struct_check ((a), (TS_TYPED)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == TEMPLATE_TYPE_PARM
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == TYPENAME_TYPE
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == TYPEOF_TYPE
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == BOUND_TEMPLATE_TEMPLATE_PARM
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == DECLTYPE_TYPE
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == TRAIT_TYPE
|| ((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code) == DEPENDENT_OPERATOR_TYPE
) || (((((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code)) == RECORD_TYPE
|| (((enum tree_code) (((contains_struct_check ((a), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type))->base.code)) == UNION_TYPE
) && ((tree_class_check ((((contains_struct_check ((a
), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 919, __FUNCTION__))->type_common.lang_flag_5)))
)
920 {
921 o = build_new_op (loc, CO_AWAIT_EXPR, LOOKUP_NORMAL((1 << 0)), a, NULL_TREE(tree) nullptr,
922 NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr, NULLnullptr, tf_warning_or_error);
923 /* If no viable functions are found, o is a. */
924 if (!o || o == error_mark_nodeglobal_trees[TI_ERROR_MARK])
925 o = a;
926 else if (flag_exceptionsglobal_options.x_flag_exceptions && suspend_kind == FINAL_SUSPEND_POINT)
927 {
928 /* We found an overload for co_await(), diagnose throwing cases. */
929 if (TREE_CODE (o)((enum tree_code) (o)->base.code) == TARGET_EXPR
930 && coro_diagnose_throwing_final_aw_expr (o))
931 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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)((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 935, __FUNCTION__))->typed.type)
;
936 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (a_type)(((tree_class_check ((a_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 936, __FUNCTION__))->type_common.lang_flag_4))
)
937 if (tree dummy
938 = build_special_member_call (a, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
939 NULLnullptr, a_type, LOOKUP_NORMAL((1 << 0)),
940 tf_none))
941 {
942 if (CONVERT_EXPR_P (dummy)((((enum tree_code) (dummy)->base.code)) == NOP_EXPR || ((
(enum tree_code) (dummy)->base.code)) == CONVERT_EXPR)
)
943 dummy = TREE_OPERAND (dummy, 0)(*((const_cast<tree*> (tree_operand_check ((dummy), (0)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 943, __FUNCTION__)))))
;
944 dummy = TREE_OPERAND (CALL_EXPR_FN (dummy), 0)(*((const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((dummy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 944, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 944, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 944, __FUNCTION__)))))
;
945 if (coro_diagnose_throwing_fn (dummy))
946 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
947 }
948 }
949 }
950 else
951 o = a; /* This is most likely about to fail anyway. */
952
953 tree o_type = TREE_TYPE (o)((contains_struct_check ((o), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 953, __FUNCTION__))->typed.type)
;
954 if (o_type && !VOID_TYPE_P (o_type)(((enum tree_code) (o_type)->base.code) == VOID_TYPE))
955 o_type = complete_type_or_else (o_type, o);
956
957 if (!o_type)
958 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
959
960 if (TREE_CODE (o_type)((enum tree_code) (o_type)->base.code) != RECORD_TYPE)
961 {
962 error_at (loc, "awaitable type %qT is not a structure",
963 o_type);
964 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK])
971 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
972 tree awsp_meth
973 = lookup_awaitable_member (o_type, coro_await_suspend_identifier, loc);
974 if (!awsp_meth || awsp_meth == error_mark_nodeglobal_trees[TI_ERROR_MARK])
975 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK])
982 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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)(o) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((o)))))
;
994 if (INDIRECT_REF_P (e_proxy)(((enum tree_code) (e_proxy)->base.code) == INDIRECT_REF))
995 e_proxy = TREE_OPERAND (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check ((e_proxy), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 995, __FUNCTION__)))))
;
996 while (TREE_CODE (e_proxy)((enum tree_code) (e_proxy)->base.code) == COMPONENT_REF)
997 {
998 e_proxy = TREE_OPERAND (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check ((e_proxy), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 998, __FUNCTION__)))))
;
999 if (INDIRECT_REF_P (e_proxy)(((enum tree_code) (e_proxy)->base.code) == INDIRECT_REF))
1000 e_proxy = TREE_OPERAND (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check ((e_proxy), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1000, __FUNCTION__)))))
;
1001 if (TREE_CODE (e_proxy)((enum tree_code) (e_proxy)->base.code) == CALL_EXPR)
1002 {
1003 /* We could have operator-> here too. */
1004 tree op = TREE_OPERAND (CALL_EXPR_FN (e_proxy), 0)(*((const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((e_proxy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1004, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1004, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1004, __FUNCTION__)))))
;
1005 if (DECL_OVERLOADED_OPERATOR_P (op)(((tree_not_check2 (((tree_check ((((contains_struct_check ((
op), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1005, __FUNCTION__))->decl_minimal.name)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1005, __FUNCTION__, (IDENTIFIER_NODE)))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1005, __FUNCTION__, (TREE_VEC), (SSA_NAME)))->base.u.bits
.lang_flag_2))
1006 && DECL_OVERLOADED_OPERATOR_IS (op, COMPONENT_REF)((__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) (op)->base.code) == TEMPLATE_DECL ? (
(struct tree_template_decl *)(const_cast<union tree_node *
> ((((tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1006, __FUNCTION__, (TEMPLATE_DECL))))))))->result : op)
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1006, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) (op)->base.code) == FUNCTION_DECL || (((
enum tree_code) (op)->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1006, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((op),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1006, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1006, __FUNCTION__); &lt->u.fn; })->ovl_op_code) ==
OVL_OP_COMPONENT_REF)
)
1007 {
1008 e_proxy = CALL_EXPR_ARG (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check (((tree_check
((e_proxy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1008, __FUNCTION__, (CALL_EXPR)))), ((0) + 3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1008, __FUNCTION__)))))
;
1009 STRIP_NOPS (e_proxy)(e_proxy) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((e_proxy)))))
;
1010 gcc_checking_assert (TREE_CODE (e_proxy) == ADDR_EXPR)((void)(!(((enum tree_code) (e_proxy)->base.code) == ADDR_EXPR
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1010, __FUNCTION__), 0 : 0))
;
1011 e_proxy = TREE_OPERAND (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check ((e_proxy), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1011, __FUNCTION__)))))
;
1012 }
1013 }
1014 STRIP_NOPS (e_proxy)(e_proxy) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((e_proxy)))))
;
1015 }
1016
1017 /* Only build a temporary if we need it. */
1018 STRIP_NOPS (e_proxy)(e_proxy) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((e_proxy)))))
;
1019 if (TREE_CODE (e_proxy)((enum tree_code) (e_proxy)->base.code) == PARM_DECL
1020 || (VAR_P (e_proxy)(((enum tree_code) (e_proxy)->base.code) == VAR_DECL) && !is_local_temp (e_proxy)))
1021 {
1022 e_proxy = o;
1023 o = NULL_TREE(tree) nullptr; /* 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(tree) nullptr;
1038 tree awrd_call
1039 = build_new_method_call (e_proxy, awrd_meth, NULLnullptr, NULL_TREE(tree) nullptr, LOOKUP_NORMAL((1 << 0)),
1040 &awrd_func, tf_warning_or_error);
1041
1042 if (!awrd_func || !awrd_call || awrd_call == error_mark_nodeglobal_trees[TI_ERROR_MARK])
1043 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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(tree) nullptr;
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(tree) nullptr,
1054 LOOKUP_NORMAL((1 << 0)), &awsp_func, tf_warning_or_error);
1055
1056 release_tree_vector (args);
1057 if (!awsp_func || !awsp_call || awsp_call == error_mark_nodeglobal_trees[TI_ERROR_MARK])
1058 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1059
1060 bool ok = false;
1061 tree susp_return_type = TREE_TYPE (TREE_TYPE (awsp_func))((contains_struct_check ((((contains_struct_check ((awsp_func
), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1061, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1061, __FUNCTION__))->typed.type)
;
1062 if (same_type_p (susp_return_type, void_type_node)comptypes ((susp_return_type), (global_trees[TI_VOID_TYPE]), 0
)
)
1063 ok = true;
1064 else if (same_type_p (susp_return_type, boolean_type_node)comptypes ((susp_return_type), (global_trees[TI_BOOLEAN_TYPE]
), 0)
)
1065 ok = true;
1066 else if (TREE_CODE (susp_return_type)((enum tree_code) (susp_return_type)->base.code) == RECORD_TYPE
1067 && CLASS_TYPE_P (susp_return_type)(((((enum tree_code) (susp_return_type)->base.code)) == RECORD_TYPE
|| (((enum tree_code) (susp_return_type)->base.code)) == UNION_TYPE
) && ((tree_class_check ((susp_return_type), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1067, __FUNCTION__))->type_common.lang_flag_5))
1068 && CLASSTYPE_TEMPLATE_INFO (susp_return_type)(((tree_class_check (((tree_check3 ((susp_return_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1068, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1068, __FUNCTION__))->type_non_common.lang_1))
)
1069 {
1070 tree tt = CLASSTYPE_TI_TEMPLATE (susp_return_type)((struct tree_template_info*)(tree_check (((((tree_class_check
(((tree_check3 ((susp_return_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1070, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1070, __FUNCTION__))->type_non_common.lang_1))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1070, __FUNCTION__, (TEMPLATE_INFO))))->tmpl
;
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_nodeglobal_trees[TI_ERROR_MARK];
1080 }
1081
1082 /* Finally, the type of e.await_resume() is the co_await's type. */
1083 tree awrs_func = NULL_TREE(tree) nullptr;
1084 tree awrs_call
1085 = build_new_method_call (e_proxy, awrs_meth, NULLnullptr, NULL_TREE(tree) nullptr, LOOKUP_NORMAL((1 << 0)),
1086 &awrs_func, tf_warning_or_error);
1087
1088 if (!awrs_func || !awrs_call || awrs_call == error_mark_nodeglobal_trees[TI_ERROR_MARK])
1089 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1090
1091 if (flag_exceptionsglobal_options.x_flag_exceptions && suspend_kind == FINAL_SUSPEND_POINT)
1092 {
1093 if (coro_diagnose_throwing_fn (awrd_func))
1094 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1095 if (coro_diagnose_throwing_fn (awsp_func))
1096 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1097 if (coro_diagnose_throwing_fn (awrs_func))
1098 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1099 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (o_type)(((tree_class_check ((o_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1099, __FUNCTION__))->type_common.lang_flag_4))
)
1100 if (tree dummy
1101 = build_special_member_call (e_proxy, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
1102 NULLnullptr, o_type, LOOKUP_NORMAL((1 << 0)),
1103 tf_none))
1104 {
1105 if (CONVERT_EXPR_P (dummy)((((enum tree_code) (dummy)->base.code)) == NOP_EXPR || ((
(enum tree_code) (dummy)->base.code)) == CONVERT_EXPR)
)
1106 dummy = TREE_OPERAND (dummy, 0)(*((const_cast<tree*> (tree_operand_check ((dummy), (0)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1106, __FUNCTION__)))))
;
1107 dummy = TREE_OPERAND (CALL_EXPR_FN (dummy), 0)(*((const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((dummy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1107, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1107, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1107, __FUNCTION__)))))
;
1108 if (coro_diagnose_throwing_fn (dummy))
1109 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1117, __FUNCTION__)))))
= awrd_call; /* await_ready(). */
1118 TREE_VEC_ELT (awaiter_calls, 1)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1118, __FUNCTION__)))))
= awsp_call; /* await_suspend(). */
1119 tree te = NULL_TREE(tree) nullptr;
1120 if (TREE_CODE (awrs_call)((enum tree_code) (awrs_call)->base.code) == TARGET_EXPR)
1121 {
1122 te = awrs_call;
1123 awrs_call = TREE_OPERAND (awrs_call, 1)(*((const_cast<tree*> (tree_operand_check ((awrs_call),
(1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1123, __FUNCTION__)))))
;
1124 }
1125 TREE_VEC_ELT (awaiter_calls, 2)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1125, __FUNCTION__)))))
= awrs_call; /* await_resume(). */
1126
1127 if (REFERENCE_REF_P (e_proxy)((((enum tree_code) (e_proxy)->base.code) == INDIRECT_REF)
&& ((contains_struct_check (((*((const_cast<tree*
> (tree_operand_check ((e_proxy), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1127, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1127, __FUNCTION__))->typed.type) && (((enum tree_code
) (((contains_struct_check (((*((const_cast<tree*> (tree_operand_check
(((e_proxy)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1127, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1127, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE
))
)
1128 e_proxy = TREE_OPERAND (e_proxy, 0)(*((const_cast<tree*> (tree_operand_check ((e_proxy), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1128, __FUNCTION__)))))
;
1129
1130 tree await_expr = build5_loc (loc, CO_AWAIT_EXPR,
1131 TREE_TYPE (TREE_TYPE (awrs_func))((contains_struct_check ((((contains_struct_check ((awrs_func
), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1131, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1131, __FUNCTION__))->typed.type)
,
1132 a, e_proxy, o, awaiter_calls,
1133 build_int_cst (integer_type_nodeinteger_types[itk_int],
1134 (int) suspend_kind));
1135 TREE_SIDE_EFFECTS (await_expr)((non_type_check ((await_expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1135, __FUNCTION__))->base.side_effects_flag)
= true;
1136 if (te)
1137 {
1138 TREE_OPERAND (te, 1)(*((const_cast<tree*> (tree_operand_check ((te), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1138, __FUNCTION__)))))
= await_expr;
1139 TREE_SIDE_EFFECTS (te)((non_type_check ((te), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1139, __FUNCTION__))->base.side_effects_flag)
= true;
1140 await_expr = te;
1141 }
1142 SET_EXPR_LOCATION (await_expr, loc)(expr_check (((await_expr)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1142, __FUNCTION__))->exp.locus = (loc)
;
1143 return convert_from_reference (await_expr);
1144}
1145
1146tree
1147finish_co_await_expr (location_t kw, tree expr)
1148{
1149 if (!expr || error_operand_p (expr))
1150 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1151
1152 if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
1153 "co_await"))
1154 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1155
1156 /* The current function has now become a coroutine, if it wasn't already. */
1157 DECL_COROUTINE_P (current_function_decl)(__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__)))->base.code) == TEMPLATE_DECL ? ((struct
tree_template_decl *)(const_cast<union tree_node *> ((
((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__)))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__)))->base.code) == FUNCTION_DECL || ((
(enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__)))->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check (((contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1157, __FUNCTION__); &lt->u.fn; })->coroutine_p)
= 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_declscope_chain->x_processing_template_decl)
1172 {
1173 tree aw_expr = build5_loc (kw, CO_AWAIT_EXPR, unknown_type_nodecp_global_trees[CPTI_UNKNOWN_TYPE], expr,
1174 NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr,
1175 integer_zero_nodeglobal_trees[TI_INTEGER_ZERO]);
1176 TREE_SIDE_EFFECTS (aw_expr)((non_type_check ((aw_expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1176, __FUNCTION__))->base.side_effects_flag)
= 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_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK])
1193 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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(tree) nullptr, LOOKUP_NORMAL((1 << 0)),
1203 NULLnullptr, 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_nodeglobal_trees[TI_ERROR_MARK])
1211 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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
1222tree
1223finish_co_yield_expr (location_t kw, tree expr)
1224{
1225 if (!expr || error_operand_p (expr))
1226 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK];
1232
1233 /* The current function has now become a coroutine, if it wasn't already. */
1234 DECL_COROUTINE_P (current_function_decl)(__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__)))->base.code) == TEMPLATE_DECL ? ((struct
tree_template_decl *)(const_cast<union tree_node *> ((
((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__)))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__)))->base.code) == FUNCTION_DECL || ((
(enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__)))->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check (((contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1234, __FUNCTION__); &lt->u.fn; })->coroutine_p)
= 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_declscope_chain->x_processing_template_decl)
1245 return build2_loc (kw, CO_YIELD_EXPR, unknown_type_nodecp_global_trees[CPTI_UNKNOWN_TYPE], expr, NULL_TREE(tree) nullptr);
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_nodeglobal_trees[TI_ERROR_MARK];
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, NULLnullptr,
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_nodeglobal_trees[TI_ERROR_MARK])
1270 {
1271 if (REFERENCE_REF_P (op)((((enum tree_code) (op)->base.code) == INDIRECT_REF) &&
((contains_struct_check (((*((const_cast<tree*> (tree_operand_check
((op), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1271, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1271, __FUNCTION__))->typed.type) && (((enum tree_code
) (((contains_struct_check (((*((const_cast<tree*> (tree_operand_check
(((op)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1271, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1271, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE
))
)
1272 op = TREE_OPERAND (op, 0)(*((const_cast<tree*> (tree_operand_check ((op), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1272, __FUNCTION__)))))
;
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)((enum tree_code) (op)->base.code) == TARGET_EXPR)
1277 {
1278 tree t = TREE_OPERAND (op, 1)(*((const_cast<tree*> (tree_operand_check ((op), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1278, __FUNCTION__)))))
;
1279 t = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1279, __FUNCTION__))->typed.type)
, expr, t);
1280 TREE_OPERAND (op, 1)(*((const_cast<tree*> (tree_operand_check ((op), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1280, __FUNCTION__)))))
= t;
1281 }
1282 else
1283 op = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (op)((contains_struct_check ((op), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1283, __FUNCTION__))->typed.type)
, expr, op);
1284 TREE_SIDE_EFFECTS (op)((non_type_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1284, __FUNCTION__))->base.side_effects_flag)
= 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
1297tree
1298finish_co_return_stmt (location_t kw, tree expr)
1299{
1300 if (expr)
1301 STRIP_ANY_LOCATION_WRAPPER (expr)(expr) = tree_strip_any_location_wrapper ((const_cast<union
tree_node *> (((expr)))))
;
1302
1303 if (error_operand_p (expr))
1304 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK];
1311
1312 /* The current function has now become a coroutine, if it wasn't
1313 already. */
1314 DECL_COROUTINE_P (current_function_decl)(__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__)))->base.code) == TEMPLATE_DECL ? ((struct
tree_template_decl *)(const_cast<union tree_node *> ((
((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__)))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__)))->base.code) == FUNCTION_DECL || ((
(enum tree_code) ((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__)))->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check (((contains_struct_check ((current_function_decl
), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check (((contains_struct_check
((current_function_decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1314, __FUNCTION__); &lt->u.fn; })->coroutine_p)
= 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_declscope_chain->x_processing_template_decl
1323 && check_for_bare_parameter_packs (expr))
1324 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1325
1326 /* Defer expansion when we are processing a template; see FIXME in the
1327 co_await code. */
1328 if (processing_template_declscope_chain->x_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_nodeglobal_trees[TI_VOID_TYPE],
1333 expr, NULL_TREE(tree) nullptr);
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_nodeglobal_trees[TI_ERROR_MARK];
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_declscope_chain->x_processing_template_decl && warn_sequence_pointglobal_options.x_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_declscope_chain->x_processing_template_decl)
1355 expr = build_non_dependent_expr (expr);
1356
1357 if (error_operand_p (expr))
1358 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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_nodeglobal_trees[TI_ERROR_MARK];
Value stored to 'co_ret_call' during its initialization is never read
1364 if (expr == NULL_TREE(tree) nullptr || VOID_TYPE_P (TREE_TYPE (expr))(((enum tree_code) (((contains_struct_check ((expr), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1364, __FUNCTION__))->typed.type))->base.code) == VOID_TYPE
)
)
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, NULLnullptr,
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)((current_function_decl)->base.volatile_flag))
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_nodeglobal_trees[TI_VOID_TYPE], 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
1403tree
1404coro_validate_builtin_call (tree call, tsubst_flags_t)
1405{
1406 tree fn = TREE_OPERAND (CALL_EXPR_FN (call), 0)(*((const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((call), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1406, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1406, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1406, __FUNCTION__)))))
;
1407
1408 gcc_checking_assert (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)((void)(!(((built_in_class) (tree_check ((fn), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1408, __FUNCTION__, (FUNCTION_DECL)))->function_decl.built_in_class
) == BUILT_IN_NORMAL) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1408, __FUNCTION__), 0 : 0))
;
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)(*((const_cast<tree*> (tree_operand_check (((tree_check
((call), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1420, __FUNCTION__, (CALL_EXPR)))), ((1) + 3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1420, __FUNCTION__)))))
;
1421 location_t loc = EXPR_LOCATION (arg)((((arg)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((arg))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((arg))->base.code))]) <= tcc_expression
)) ? (arg)->exp.locus : ((location_t) 0))
;
1422
1423 /* We expect alignof expressions in templates. */
1424 if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == NON_DEPENDENT_EXPR
1425 && TREE_CODE (TREE_OPERAND (arg, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check
((arg), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1425, __FUNCTION__))))))->base.code)
== ALIGNOF_EXPR)
1426 ;
1427 else if (!TREE_CONSTANT (arg)((non_type_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1427, __FUNCTION__))->base.constant_flag)
)
1428 {
1429 error_at (loc, "the align argument to %<__builtin_coro_promise%>"
1430 " must be a constant");
1431 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1432 }
1433 /* Argument 2 is the direction - to / from handle address to promise
1434 address. */
1435 arg = CALL_EXPR_ARG (call, 2)(*((const_cast<tree*> (tree_operand_check (((tree_check
((call), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1435, __FUNCTION__, (CALL_EXPR)))), ((2) + 3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1435, __FUNCTION__)))))
;
1436 loc = EXPR_LOCATION (arg)((((arg)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((arg))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((arg))->base.code))]) <= tcc_expression
)) ? (arg)->exp.locus : ((location_t) 0))
;
1437 if (!TREE_CONSTANT (arg)((non_type_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1437, __FUNCTION__))->base.constant_flag)
)
1438 {
1439 error_at (loc, "the direction argument to"
1440 " %<__builtin_coro_promise%> must be a constant");
1441 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
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
1503static tree
1504coro_build_expr_stmt (tree expr, location_t loc)
1505{
1506 return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr));
1507}
1508
1509static tree
1510coro_build_cvt_void_expr_stmt (tree expr, location_t loc)
1511{
1512 tree t = build1 (CONVERT_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], 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
1519static tree
1520coro_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)((contains_struct_check ((res), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1524, __FUNCTION__))->decl_minimal.locus)
= loc;
1525 DECL_CONTEXT (res)((contains_struct_check ((res), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1525, __FUNCTION__))->decl_minimal.context)
= ctx;
1526 DECL_ARTIFICIAL (res)((contains_struct_check ((res), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1526, __FUNCTION__))->decl_common.artificial_flag)
= true;
1527 DECL_INITIAL (res)((contains_struct_check ((res), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1527, __FUNCTION__))->decl_common.initial)
= init;
1528 return res;
1529}
1530
1531static tree
1532coro_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)(__builtin_constant_p (name) ? get_identifier_with_length ((name
), strlen (name)) : 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
1542static tree
1543create_anon_label_with_ctx (location_t loc, tree ctx)
1544{
1545 tree lab = build_decl (loc, LABEL_DECL, NULL_TREE(tree) nullptr, void_type_nodeglobal_trees[TI_VOID_TYPE]);
1546
1547 DECL_CONTEXT (lab)((contains_struct_check ((lab), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1547, __FUNCTION__))->decl_minimal.context)
= ctx;
1548 DECL_ARTIFICIAL (lab)((contains_struct_check ((lab), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1548, __FUNCTION__))->decl_common.artificial_flag)
= true;
1549 DECL_IGNORED_P (lab)((contains_struct_check ((lab), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1549, __FUNCTION__))->decl_common.ignored_flag)
= true;
1550 TREE_USED (lab)((lab)->base.used_flag) = true;
1551 return lab;
1552}
1553
1554/* 2. Create a named label in the specified context. */
1555
1556static tree
1557create_named_label_with_ctx (location_t loc, const char *name, tree ctx)
1558{
1559 tree lab_id = get_identifier (name)(__builtin_constant_p (name) ? get_identifier_with_length ((name
), strlen (name)) : get_identifier (name))
;
1560 tree lab = define_label (loc, lab_id);
1561 DECL_CONTEXT (lab)((contains_struct_check ((lab), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1561, __FUNCTION__))->decl_minimal.context)
= ctx;
1562 DECL_ARTIFICIAL (lab)((contains_struct_check ((lab), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1562, __FUNCTION__))->decl_common.artificial_flag)
= true;
1563 TREE_USED (lab)((lab)->base.used_flag) = true;
1564 return lab;
1565}
1566
1567struct proxy_replace
1568{
1569 tree from, to;
1570};
1571
1572static tree
1573replace_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(tree) nullptr;
1585}
1586
1587/* Support for expansion of co_await statements. */
1588
1589struct 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
1610static tree
1611co_await_find_in_subtree (tree *stmt, int *, void *d)
1612{
1613 tree **p = (tree **) d;
1614 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == CO_AWAIT_EXPR)
1615 {
1616 *p = stmt;
1617 return *stmt;
1618 }
1619 return NULL_TREE(tree) nullptr;
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
1642static tree *
1643expand_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)((((*stmt)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((*stmt))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((*stmt))->base.code))]) <= tcc_expression
)) ? (*stmt)->exp.locus : ((location_t) 0))
;
1652 tree var = TREE_OPERAND (saved_co_await, 1)(*((const_cast<tree*> (tree_operand_check ((saved_co_await
), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1652, __FUNCTION__)))))
; /* frame slot. */
1653 tree expr = TREE_OPERAND (saved_co_await, 2)(*((const_cast<tree*> (tree_operand_check ((saved_co_await
), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1653, __FUNCTION__)))))
; /* initializer. */
1654 tree awaiter_calls = TREE_OPERAND (saved_co_await, 3)(*((const_cast<tree*> (tree_operand_check ((saved_co_await
), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1654, __FUNCTION__)))))
;
1655
1656 tree source = TREE_OPERAND (saved_co_await, 4)(*((const_cast<tree*> (tree_operand_check ((saved_co_await
), (4), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1656, __FUNCTION__)))))
;
1657 bool is_final = (source
1658 && TREE_INT_CST_LOW (source)((unsigned long) (*tree_int_cst_elt_check ((source), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1658, __FUNCTION__)))
== (int) FINAL_SUSPEND_POINT);
1659 bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var))(((tree_class_check ((((contains_struct_check ((var), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1659, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1659, __FUNCTION__))->type_common.lang_flag_4))
;
1660 int resume_point = data->index;
1661 size_t bufsize = sizeof ("destroy.") + 10;
1662 char *buf = (char *) alloca (bufsize)__builtin_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)((contains_struct_check ((var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1669, __FUNCTION__))->typed.type)
;
1670 tree stmt_list = NULLnullptr;
1671 tree r;
1672 tree *await_init = NULLnullptr;
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)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1685, __FUNCTION__)))))
; /* await_ready(). */
1686 /* Convert to bool, if necessary. */
1687 if (TREE_CODE (TREE_TYPE (ready_cond))((enum tree_code) (((contains_struct_check ((ready_cond), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1687, __FUNCTION__))->typed.type))->base.code)
!= BOOLEAN_TYPE)
1688 ready_cond = cp_convert (boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], 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_nodeglobal_trees[TI_BOOLEAN_TYPE], ready_cond);
1695
1696 tree body_list = NULLnullptr;
1697 tree susp_idx = build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], data->index);
1698 r = build2_loc (loc, MODIFY_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], 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)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1713, __FUNCTION__)))))
; /* await_suspend(). */
1714 tree susp_type = TREE_TYPE (suspend)((contains_struct_check ((suspend), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1714, __FUNCTION__))->typed.type)
;
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)(((enum tree_code) (susp_type)->base.code) == VOID_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)((enum tree_code) (susp_type)->base.code) == BOOLEAN_TYPE)
1726 {
1727 /* Boolean return, continue if the call returns false. */
1728 suspend = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], suspend);
1729 suspend
1730 = build1_loc (loc, CLEANUP_POINT_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], suspend);
1731 tree go_on = build1_loc (loc, GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], resume_label);
1732 r = build3_loc (loc, COND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], suspend, go_on,
1733 empty_list);
1734 append_to_statement_list (r, &body_list);
1735 }
1736 else
1737 {
1738 r = suspend;
1739 if (!same_type_ignoring_top_level_qualifiers_p (susp_type,
1740 void_coro_handle_type))
1741 r = build1_loc (loc, VIEW_CONVERT_EXPR, void_coro_handle_type, r);
1742 r = cp_build_init_expr (loc, data->conthand, r);
1743 r = build1 (CONVERT_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], r);
1744 append_to_statement_list (r, &body_list);
1745 is_cont = true;
1746 }
1747
1748 tree d_l = build_address (destroy_label);
1749 tree r_l = build_address (resume_label);
1750 tree susp = build_address (data->cororet);
1751 tree cont = build_address (data->corocont);
1752 tree final_susp = build_int_cst (integer_type_nodeinteger_types[itk_int], is_final ? 1 : 0);
1753
1754 susp_idx = build_int_cst (integer_type_nodeinteger_types[itk_int], data->index);
1755
1756 tree sw = begin_switch_stmt ();
1757 tree cond = build_decl (loc, VAR_DECL, NULL_TREE(tree) nullptr, integer_type_nodeinteger_types[itk_int]);
1758 DECL_ARTIFICIAL (cond)((contains_struct_check ((cond), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1758, __FUNCTION__))->decl_common.artificial_flag)
= 1;
1759 DECL_IGNORED_P (cond)((contains_struct_check ((cond), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1759, __FUNCTION__))->decl_common.ignored_flag)
= 1;
1760 layout_decl (cond, 0);
1761
1762 r = build_call_expr_internal_loc (loc, IFN_CO_YIELD, integer_type_nodeinteger_types[itk_int], 5,
1763 susp_idx, final_susp, r_l, d_l,
1764 data->coro_fp);
1765 r = cp_build_init_expr (cond, r);
1766 finish_switch_cond (r, sw);
1767 r = build_case_label (build_int_cst (integer_type_nodeinteger_types[itk_int], 0), NULL_TREE(tree) nullptr,
1768 create_anon_label_with_ctx (loc, actor));
1769 add_stmt (r); /* case 0: */
1770 /* Implement the suspend, a scope exit without clean ups. */
1771 r = build_call_expr_internal_loc (loc, IFN_CO_SUSPN, void_type_nodeglobal_trees[TI_VOID_TYPE], 1,
1772 is_cont ? cont : susp);
1773 r = coro_build_cvt_void_expr_stmt (r, loc);
1774 add_stmt (r); /* goto ret; */
1775 r = build_case_label (build_int_cst (integer_type_nodeinteger_types[itk_int], 1), NULL_TREE(tree) nullptr,
1776 create_anon_label_with_ctx (loc, actor));
1777 add_stmt (r); /* case 1: */
1778 r = build1_loc (loc, GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], resume_label);
1779 add_stmt (r); /* goto resume; */
1780 r = build_case_label (NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr,
1781 create_anon_label_with_ctx (loc, actor));
1782 add_stmt (r); /* default:; */
1783 r = build1_loc (loc, GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], destroy_label);
1784 add_stmt (r); /* goto destroy; */
1785
1786 /* part of finish switch. */
1787 SWITCH_STMT_BODY (sw)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1787, __FUNCTION__, (SWITCH_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1787, __FUNCTION__)))))
= pop_stmt_list (SWITCH_STMT_BODY (sw)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1787, __FUNCTION__, (SWITCH_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1787, __FUNCTION__)))))
);
1788 pop_switch ();
1789 tree scope = SWITCH_STMT_SCOPE (sw)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1789, __FUNCTION__, (SWITCH_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1789, __FUNCTION__)))))
;
1790 SWITCH_STMT_SCOPE (sw)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1790, __FUNCTION__, (SWITCH_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1790, __FUNCTION__)))))
= NULLnullptr;
1791 r = do_poplevel (scope);
1792 append_to_statement_list (r, &body_list);
1793
1794 destroy_label = build_stmt (loc, LABEL_EXPR, destroy_label);
1795 append_to_statement_list (destroy_label, &body_list);
1796 if (needs_dtor)
1797 {
1798 tree dtor = build_special_member_call (var, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
1799 NULLnullptr, await_type, LOOKUP_NORMAL((1 << 0)),
1800 tf_warning_or_error);
1801 append_to_statement_list (dtor, &body_list);
1802 }
1803 r = build1_loc (loc, GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], data->cleanup);
1804 append_to_statement_list (r, &body_list);
1805
1806 r = build3_loc (loc, COND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], ready_cond, body_list,
1807 empty_list);
1808
1809 append_to_statement_list (r, &stmt_list);
1810
1811 /* Resume point. */
1812 resume_label = build_stmt (loc, LABEL_EXPR, resume_label);
1813 append_to_statement_list (resume_label, &stmt_list);
1814
1815 /* This will produce the value (if one is provided) from the co_await
1816 expression. */
1817 tree resume_call = TREE_VEC_ELT (awaiter_calls, 2)(*((const_cast<tree *> (tree_vec_elt_check ((awaiter_calls
), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1817, __FUNCTION__)))))
; /* await_resume(). */
1818 if (REFERENCE_REF_P (resume_call)((((enum tree_code) (resume_call)->base.code) == INDIRECT_REF
) && ((contains_struct_check (((*((const_cast<tree
*> (tree_operand_check ((resume_call), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1818, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1818, __FUNCTION__))->typed.type) && (((enum tree_code
) (((contains_struct_check (((*((const_cast<tree*> (tree_operand_check
(((resume_call)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1818, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1818, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE
))
)
1819 /* Sink to await_resume call_expr. */
1820 resume_call = TREE_OPERAND (resume_call, 0)(*((const_cast<tree*> (tree_operand_check ((resume_call
), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1820, __FUNCTION__)))))
;
1821
1822 *await_expr = resume_call; /* Replace the co_await expr with its result. */
1823 append_to_statement_list_force (saved_statement, &stmt_list);
1824 /* Get a pointer to the revised statement. */
1825 tree *revised = tsi_stmt_ptr (tsi_last (stmt_list));
1826 if (needs_dtor)
1827 {
1828 tree dtor = build_special_member_call (var, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
1829 NULLnullptr, await_type, LOOKUP_NORMAL((1 << 0)),
1830 tf_warning_or_error);
1831 append_to_statement_list (dtor, &stmt_list);
1832 }
1833 data->index += 2;
1834
1835 /* Replace the original statement with the expansion. */
1836 *stmt = stmt_list;
1837
1838 /* Now, if the awaitable had an initializer, expand any awaits that might
1839 be embedded in it. */
1840 tree *aw_expr_ptr;
1841 if (await_init &&
1842 cp_walk_tree (await_init, co_await_find_in_subtree, &aw_expr_ptr, NULL)walk_tree_1 (await_init, co_await_find_in_subtree, &aw_expr_ptr
, nullptr, cp_walk_subtrees)
)
1843 expand_one_await_expression (await_init, aw_expr_ptr, d);
1844
1845 /* Expand any more await expressions in the original statement. */
1846 if (cp_walk_tree (revised, co_await_find_in_subtree, &aw_expr_ptr, NULL)walk_tree_1 (revised, co_await_find_in_subtree, &aw_expr_ptr
, nullptr, cp_walk_subtrees)
)
1847 expand_one_await_expression (revised, aw_expr_ptr, d);
1848
1849 return NULLnullptr;
1850}
1851
1852/* Check to see if a statement contains at least one await expression, if
1853 so, then process that. */
1854
1855static tree
1856process_one_statement (tree *stmt, void *d)
1857{
1858 tree *aw_expr_ptr;
1859 if (cp_walk_tree (stmt, co_await_find_in_subtree, &aw_expr_ptr, NULL)walk_tree_1 (stmt, co_await_find_in_subtree, &aw_expr_ptr
, nullptr, cp_walk_subtrees)
)
1860 expand_one_await_expression (stmt, aw_expr_ptr, d);
1861 return NULL_TREE(tree) nullptr;
1862}
1863
1864static tree
1865await_statement_expander (tree *stmt, int *do_subtree, void *d)
1866{
1867 tree res = NULL_TREE(tree) nullptr;
1868
1869 /* Process a statement at a time. */
1870 if (STATEMENT_CLASS_P (*stmt)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code
) (*stmt)->base.code))] == tcc_statement)
|| TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == BIND_EXPR)
1871 return NULL_TREE(tree) nullptr; /* Just process the sub-trees. */
1872 else if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == STATEMENT_LIST)
1873 {
1874 for (tree &s : tsi_range (*stmt))
1875 {
1876 res = cp_walk_tree (&s, await_statement_expander,walk_tree_1 (&s, await_statement_expander, d, nullptr, cp_walk_subtrees
)
1877 d, NULL)walk_tree_1 (&s, await_statement_expander, d, nullptr, cp_walk_subtrees
)
;
1878 if (res)
1879 return res;
1880 }
1881 *do_subtree = 0; /* Done subtrees. */
1882 }
1883 else if (EXPR_P (*stmt)((tree_code_type_tmpl <0>::tree_code_type[(int) (((enum
tree_code) (*stmt)->base.code))]) >= tcc_reference &&
(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum
tree_code) (*stmt)->base.code))]) <= tcc_expression)
)
1884 {
1885 process_one_statement (stmt, d);
1886 *do_subtree = 0; /* Done subtrees. */
1887 }
1888
1889 /* Continue statement walk, where required. */
1890 return res;
1891}
1892
1893/* Suspend point hash_map. */
1894
1895struct suspend_point_info
1896{
1897 /* coro frame field type. */
1898 tree awaitable_type;
1899 /* coro frame field name. */
1900 tree await_field_id;
1901};
1902
1903static hash_map<tree, suspend_point_info> *suspend_points;
1904
1905struct await_xform_data
1906{
1907 tree actor_fn; /* Decl for context. */
1908 tree actor_frame;
1909};
1910
1911/* When we built the await expressions, we didn't know the coro frame
1912 layout, therefore no idea where to find the promise or where to put
1913 the awaitables. Now we know these things, fill them in. */
1914
1915static tree
1916transform_await_expr (tree await_expr, await_xform_data *xform)
1917{
1918 suspend_point_info *si = suspend_points->get (await_expr);
1919 location_t loc = EXPR_LOCATION (await_expr)((((await_expr)) && ((tree_code_type_tmpl <0>::
tree_code_type[(int) (((enum tree_code) ((await_expr))->base
.code))]) >= tcc_reference && (tree_code_type_tmpl
<0>::tree_code_type[(int) (((enum tree_code) ((await_expr
))->base.code))]) <= tcc_expression)) ? (await_expr)->
exp.locus : ((location_t) 0))
;
1920 if (!si)
1921 {
1922 error_at (loc, "no suspend point info for %qD", await_expr);
1923 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
1924 }
1925
1926 /* So, on entry, we have:
1927 in : CO_AWAIT_EXPR (a, e_proxy, o, awr_call_vector, mode)
1928 We no longer need a [it had diagnostic value, maybe?]
1929 We need to replace the e_proxy in the awr_call. */
1930
1931 tree coro_frame_type = TREE_TYPE (xform->actor_frame)((contains_struct_check ((xform->actor_frame), (TS_TYPED),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1931, __FUNCTION__))->typed.type)
;
1932
1933 /* If we have a frame var for the awaitable, get a reference to it. */
1934 proxy_replace data;
1935 if (si->await_field_id)
1936 {
1937 tree as_m
1938 = lookup_member (coro_frame_type, si->await_field_id,
1939 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
1940 tree as = build_class_member_access_expr (xform->actor_frame, as_m,
1941 NULL_TREE(tree) nullptr, true,
1942 tf_warning_or_error);
1943
1944 /* Replace references to the instance proxy with the frame entry now
1945 computed. */
1946 data.from = TREE_OPERAND (await_expr, 1)(*((const_cast<tree*> (tree_operand_check ((await_expr)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1946, __FUNCTION__)))))
;
1947 data.to = as;
1948 cp_walk_tree (&await_expr, replace_proxy, &data, NULL)walk_tree_1 (&await_expr, replace_proxy, &data, nullptr
, cp_walk_subtrees)
;
1949
1950 /* .. and replace. */
1951 TREE_OPERAND (await_expr, 1)(*((const_cast<tree*> (tree_operand_check ((await_expr)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1951, __FUNCTION__)))))
= as;
1952 }
1953
1954 return await_expr;
1955}
1956
1957/* A wrapper for the transform_await_expr function so that it can be a
1958 callback from cp_walk_tree. */
1959
1960static tree
1961transform_await_wrapper (tree *stmt, int *do_subtree, void *d)
1962{
1963 /* Set actor function as new DECL_CONTEXT of label_decl. */
1964 struct await_xform_data *xform = (struct await_xform_data *) d;
1965 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == LABEL_DECL
1966 && DECL_CONTEXT (*stmt)((contains_struct_check ((*stmt), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1966, __FUNCTION__))->decl_minimal.context)
!= xform->actor_fn)
1967 DECL_CONTEXT (*stmt)((contains_struct_check ((*stmt), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1967, __FUNCTION__))->decl_minimal.context)
= xform->actor_fn;
1968
1969 /* We should have already lowered co_yields to their co_await. */
1970 gcc_checking_assert (TREE_CODE (*stmt) != CO_YIELD_EXPR)((void)(!(((enum tree_code) (*stmt)->base.code) != CO_YIELD_EXPR
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 1970, __FUNCTION__), 0 : 0))
;
1971 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) != CO_AWAIT_EXPR)
1972 return NULL_TREE(tree) nullptr;
1973
1974 tree await_expr = *stmt;
1975 *stmt = transform_await_expr (await_expr, xform);
1976 if (*stmt == error_mark_nodeglobal_trees[TI_ERROR_MARK])
1977 *do_subtree = 0;
1978 return NULL_TREE(tree) nullptr;
1979}
1980
1981/* This caches information that we determine about function params,
1982 their uses and copies in the coroutine frame. */
1983
1984struct param_info
1985{
1986 tree field_id; /* The name of the copy in the coroutine frame. */
1987 tree copy_var; /* The local var proxy for the frame copy. */
1988 vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */
1989 tree frame_type; /* The type used to represent this parm in the frame. */
1990 tree orig_type; /* The original type of the parm (not as passed). */
1991 tree guard_var; /* If we need a DTOR on exception, this bool guards it. */
1992 tree fr_copy_dtor; /* If we need a DTOR on exception, this is it. */
1993 bool by_ref; /* Was passed by reference. */
1994 bool pt_ref; /* Was a pointer to object. */
1995 bool rv_ref; /* Was an rvalue ref. */
1996 bool trivial_dtor; /* The frame type has a trivial DTOR. */
1997 bool this_ptr; /* Is 'this' */
1998 bool lambda_cobj; /* Lambda capture object */
1999};
2000
2001struct local_var_info
2002{
2003 tree field_id;
2004 tree field_idx;
2005 tree frame_type;
2006 bool is_lambda_capture;
2007 bool is_static;
2008 bool has_value_expr_p;
2009 location_t def_loc;
2010};
2011
2012/* For figuring out what local variable usage we have. */
2013struct local_vars_transform
2014{
2015 tree context;
2016 tree actor_frame;
2017 tree coro_frame_type;
2018 location_t loc;
2019 hash_map<tree, local_var_info> *local_var_uses;
2020};
2021
2022static tree
2023transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
2024{
2025 local_vars_transform *lvd = (local_vars_transform *) d;
2026
2027 /* For each var in this bind expr (that has a frame id, which means it was
2028 accessed), build a frame reference and add it as the DECL_VALUE_EXPR. */
2029
2030 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == BIND_EXPR)
2031 {
2032 tree lvar;
2033 for (lvar = BIND_EXPR_VARS (*stmt)((*((const_cast<tree*> (tree_operand_check (((tree_check
((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2033, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2033, __FUNCTION__))))))
; lvar != NULLnullptr;
2034 lvar = DECL_CHAIN (lvar)(((contains_struct_check (((contains_struct_check ((lvar), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2034, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2034, __FUNCTION__))->common.chain))
)
2035 {
2036 bool existed;
2037 local_var_info &local_var
2038 = lvd->local_var_uses->get_or_insert (lvar, &existed);
2039 gcc_checking_assert (existed)((void)(!(existed) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2039, __FUNCTION__), 0 : 0))
;
2040
2041 /* Re-write the variable's context to be in the actor func. */
2042 DECL_CONTEXT (lvar)((contains_struct_check ((lvar), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2042, __FUNCTION__))->decl_minimal.context)
= lvd->context;
2043
2044 /* For capture proxies, this could include the decl value expr. */
2045 if (local_var.is_lambda_capture || local_var.has_value_expr_p)
2046 continue; /* No frame entry for this. */
2047
2048 /* TODO: implement selective generation of fields when vars are
2049 known not-used. */
2050 if (local_var.field_id == NULL_TREE(tree) nullptr)
2051 continue; /* Wasn't used. */
2052
2053 tree fld_ref
2054 = lookup_member (lvd->coro_frame_type, local_var.field_id,
2055 /*protect=*/1, /*want_type=*/0,
2056 tf_warning_or_error);
2057 tree fld_idx = build3 (COMPONENT_REF, TREE_TYPE (lvar)((contains_struct_check ((lvar), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2057, __FUNCTION__))->typed.type)
,
2058 lvd->actor_frame, fld_ref, NULL_TREE(tree) nullptr);
2059 local_var.field_idx = fld_idx;
2060 SET_DECL_VALUE_EXPR (lvar, fld_idx)(decl_value_expr_insert ((contains_struct_check ((lvar), (TS_DECL_WRTL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2060, __FUNCTION__)), fld_idx))
;
2061 DECL_HAS_VALUE_EXPR_P (lvar)((tree_check3 ((lvar), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2061, __FUNCTION__, (VAR_DECL), (PARM_DECL), (RESULT_DECL))
) ->decl_common.decl_flag_2)
= true;
2062 }
2063 cp_walk_tree (&BIND_EXPR_BODY (*stmt), transform_local_var_uses, d, NULL)walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2063, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2063, __FUNCTION__)))))), transform_local_var_uses, d, nullptr
, cp_walk_subtrees)
;
2064 *do_subtree = 0; /* We've done the body already. */
2065 return NULL_TREE(tree) nullptr;
2066 }
2067 return NULL_TREE(tree) nullptr;
2068}
2069
2070/* A helper to build the frame DTOR.
2071 [dcl.fct.def.coroutine] / 12
2072 The deallocation function’s name is looked up in the scope of the promise
2073 type. If this lookup fails, the deallocation function’s name is looked up
2074 in the global scope. If deallocation function lookup finds both a usual
2075 deallocation function with only a pointer parameter and a usual
2076 deallocation function with both a pointer parameter and a size parameter,
2077 then the selected deallocation function shall be the one with two
2078 parameters. Otherwise, the selected deallocation function shall be the
2079 function with one parameter. If no usual deallocation function is found
2080 the program is ill-formed. The selected deallocation function shall be
2081 called with the address of the block of storage to be reclaimed as its
2082 first argument. If a deallocation function with a parameter of type
2083 std::size_t is used, the size of the block is passed as the corresponding
2084 argument. */
2085
2086static tree
2087coro_get_frame_dtor (tree coro_fp, tree orig, tree frame_size,
2088 tree promise_type, location_t loc)
2089{
2090 tree del_coro_fr = NULL_TREE(tree) nullptr;
2091 tree frame_arg = build1 (CONVERT_EXPR, ptr_type_nodeglobal_trees[TI_PTR_TYPE], coro_fp);
2092 tree delname = ovl_op_identifier (false, DELETE_EXPR);
2093 tree fns = lookup_promise_method (orig, delname, loc,
2094 /*musthave=*/false);
2095 if (fns && BASELINK_P (fns)(((enum tree_code) (fns)->base.code) == BASELINK))
2096 {
2097 /* Look for sized version first, since this takes precedence. */
2098 vec<tree, va_gc> *args = make_tree_vector ();
2099 vec_safe_push (args, frame_arg);
2100 vec_safe_push (args, frame_size);
2101 tree dummy_promise = build_dummy_object (promise_type);
2102
2103 /* It's OK to fail for this one... */
2104 del_coro_fr = build_new_method_call (dummy_promise, fns, &args,
2105 NULL_TREE(tree) nullptr, LOOKUP_NORMAL((1 << 0)), NULLnullptr,
2106 tf_none);
2107
2108 if (!del_coro_fr || del_coro_fr == error_mark_nodeglobal_trees[TI_ERROR_MARK])
2109 {
2110 release_tree_vector (args);
2111 args = make_tree_vector_single (frame_arg);
2112 del_coro_fr = build_new_method_call (dummy_promise, fns, &args,
2113 NULL_TREE(tree) nullptr, LOOKUP_NORMAL((1 << 0)), NULLnullptr,
2114 tf_none);
2115 }
2116
2117 /* But one of them must succeed, or the program is ill-formed. */
2118 if (!del_coro_fr || del_coro_fr == error_mark_nodeglobal_trees[TI_ERROR_MARK])
2119 {
2120 error_at (loc, "%qE is provided by %qT but is not usable with"
2121 " the function signature %qD", delname, promise_type, orig);
2122 del_coro_fr = error_mark_nodeglobal_trees[TI_ERROR_MARK];
2123 }
2124 }
2125 else
2126 {
2127 del_coro_fr = build_op_delete_call (DELETE_EXPR, frame_arg, frame_size,
2128 /*global_p=*/true, /*placement=*/NULLnullptr,
2129 /*alloc_fn=*/NULLnullptr,
2130 tf_warning_or_error);
2131 if (!del_coro_fr || del_coro_fr == error_mark_nodeglobal_trees[TI_ERROR_MARK])
2132 del_coro_fr = error_mark_nodeglobal_trees[TI_ERROR_MARK];
2133 }
2134 return del_coro_fr;
2135}
2136
2137/* The actor transform. */
2138
2139static void
2140build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
2141 tree orig, hash_map<tree, local_var_info> *local_var_uses,
2142 vec<tree, va_gc> *param_dtor_list,
2143 tree resume_idx_var, unsigned body_count, tree frame_size)
2144{
2145 verify_stmt_tree (fnbody);
2146 /* Some things we inherit from the original function. */
2147 tree handle_type = get_coroutine_handle_type (orig);
2148 tree promise_type = get_coroutine_promise_type (orig);
2149 tree promise_proxy = get_coroutine_promise_proxy (orig);
2150
2151 /* One param, the coro frame pointer. */
2152 tree actor_fp = DECL_ARGUMENTS (actor)((tree_check ((actor), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2152, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
;
2153
2154 /* We have a definition here. */
2155 TREE_STATIC (actor)((actor)->base.static_flag) = 1;
2156
2157 tree actor_outer = push_stmt_list ();
2158 current_stmt_tree ()->stmts_are_full_exprs_p = 1;
2159 tree stmt = begin_compound_stmt (BCS_FN_BODY);
2160
2161 tree actor_bind = build3 (BIND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], NULLnullptr, NULLnullptr, NULLnullptr);
2162 tree top_block = make_node (BLOCK);
2163 BIND_EXPR_BLOCK (actor_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((actor_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2163, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2163, __FUNCTION__))))))
= top_block;
2164
2165 tree continuation = coro_build_artificial_var (loc, coro_actor_continue_id,
2166 void_coro_handle_type, actor,
2167 NULL_TREE(tree) nullptr);
2168
2169 BIND_EXPR_VARS (actor_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((actor_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2169, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2169, __FUNCTION__))))))
= continuation;
2170 BLOCK_VARS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2170, __FUNCTION__, (BLOCK)))->block.vars)
= BIND_EXPR_VARS (actor_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((actor_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2170, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2170, __FUNCTION__))))))
;
2171
2172 /* Link in the block associated with the outer scope of the re-written
2173 function body. */
2174 tree first = expr_first (fnbody);
2175 gcc_checking_assert (first && TREE_CODE (first) == BIND_EXPR)((void)(!(first && ((enum tree_code) (first)->base
.code) == BIND_EXPR) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2175, __FUNCTION__), 0 : 0))
;
2176 tree block = BIND_EXPR_BLOCK (first)((*((const_cast<tree*> (tree_operand_check (((tree_check
((first), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2176, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2176, __FUNCTION__))))))
;
2177 gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE)((void)(!(((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2177, __FUNCTION__, (BLOCK)))->block.supercontext) == (tree
) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2177, __FUNCTION__), 0 : 0))
;
2178 gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE)((void)(!(((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2178, __FUNCTION__, (BLOCK)))->block.chain) == (tree) nullptr
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2178, __FUNCTION__), 0 : 0))
;
2179 BLOCK_SUPERCONTEXT (block)((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2179, __FUNCTION__, (BLOCK)))->block.supercontext)
= top_block;
2180 BLOCK_SUBBLOCKS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2180, __FUNCTION__, (BLOCK)))->block.subblocks)
= block;
2181
2182 add_stmt (actor_bind);
2183 tree actor_body = push_stmt_list ();
2184
2185 /* The entry point for the actor code from the ramp. */
2186 tree actor_begin_label
2187 = create_named_label_with_ctx (loc, "actor.begin", actor);
2188 tree actor_frame = build1_loc (loc, INDIRECT_REF, coro_frame_type, actor_fp);
2189
2190 /* Declare the continuation handle. */
2191 add_decl_expr (continuation);
2192
2193 /* Re-write local vars, similarly. */
2194 local_vars_transform xform_vars_data
2195 = {actor, actor_frame, coro_frame_type, loc, local_var_uses};
2196 cp_walk_tree (&fnbody, transform_local_var_uses, &xform_vars_data, NULL)walk_tree_1 (&fnbody, transform_local_var_uses, &xform_vars_data
, nullptr, cp_walk_subtrees)
;
2197
2198 tree rat_field = lookup_member (coro_frame_type, coro_resume_index_id,
2199 1, 0, tf_warning_or_error);
2200 tree rat = build3 (COMPONENT_REF, short_unsigned_type_nodeinteger_types[itk_unsigned_short], actor_frame,
2201 rat_field, NULL_TREE(tree) nullptr);
2202
2203 tree ret_label
2204 = create_named_label_with_ctx (loc, "actor.suspend.ret", actor);
2205
2206 tree continue_label
2207 = create_named_label_with_ctx (loc, "actor.continue.ret", actor);
2208
2209 tree lsb_if = begin_if_stmt ();
2210 tree chkb0 = build2 (BIT_AND_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], rat,
2211 build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], 1));
2212 chkb0 = build2 (NE_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], chkb0,
2213 build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], 0));
2214 finish_if_stmt_cond (chkb0, lsb_if);
2215
2216 tree destroy_dispatcher = begin_switch_stmt ();
2217 finish_switch_cond (rat, destroy_dispatcher);
2218 tree ddeflab = build_case_label (NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr,
2219 create_anon_label_with_ctx (loc, actor));
2220 add_stmt (ddeflab);
2221 tree b = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
2222 b = coro_build_cvt_void_expr_stmt (b, loc);
2223 add_stmt (b);
2224
2225 /* The destroy point numbered #1 is special, in that it is reached from a
2226 coroutine that is suspended after re-throwing from unhandled_exception().
2227 This label just invokes the cleanup of promise, param copies and the
2228 frame itself. */
2229 tree del_promise_label
2230 = create_named_label_with_ctx (loc, "coro.delete.promise", actor);
2231 b = build_case_label (build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], 1), NULL_TREE(tree) nullptr,
2232 create_anon_label_with_ctx (loc, actor));
2233 add_stmt (b);
2234 add_stmt (build_stmt (loc, GOTO_EXPR, del_promise_label));
2235
2236 short unsigned lab_num = 3;
2237 for (unsigned destr_pt = 0; destr_pt < body_count; destr_pt++)
2238 {
2239 tree l_num = build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], lab_num);
2240 b = build_case_label (l_num, NULL_TREE(tree) nullptr,
2241 create_anon_label_with_ctx (loc, actor));
2242 add_stmt (b);
2243 b = build_call_expr_internal_loc (loc, IFN_CO_ACTOR, void_type_nodeglobal_trees[TI_VOID_TYPE], 1,
2244 l_num);
2245 b = coro_build_cvt_void_expr_stmt (b, loc);
2246 add_stmt (b);
2247 b = build1 (GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], CASE_LABEL (ddeflab)(*((const_cast<tree*> (tree_operand_check (((tree_check
((ddeflab), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2247, __FUNCTION__, (CASE_LABEL_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2247, __FUNCTION__)))))
);
2248 add_stmt (b);
2249 lab_num += 2;
2250 }
2251
2252 /* Insert the prototype dispatcher. */
2253 finish_switch_stmt (destroy_dispatcher);
2254
2255 finish_then_clause (lsb_if);
2256 begin_else_clause (lsb_if);
2257
2258 tree dispatcher = begin_switch_stmt ();
2259 finish_switch_cond (rat, dispatcher);
2260 b = build_case_label (build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], 0), NULL_TREE(tree) nullptr,
2261 create_anon_label_with_ctx (loc, actor));
2262 add_stmt (b);
2263 b = build1 (GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], actor_begin_label);
2264 add_stmt (b);
2265
2266 tree rdeflab = build_case_label (NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr,
2267 create_anon_label_with_ctx (loc, actor));
2268 add_stmt (rdeflab);
2269 b = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
2270 b = coro_build_cvt_void_expr_stmt (b, loc);
2271 add_stmt (b);
2272
2273 lab_num = 2;
2274 /* The final resume should be made to hit the default (trap, UB) entry
2275 although it will be unreachable via the normal entry point, since that
2276 is set to NULL on reaching final suspend. */
2277 for (unsigned resu_pt = 0; resu_pt < body_count; resu_pt++)
2278 {
2279 tree l_num = build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], lab_num);
2280 b = build_case_label (l_num, NULL_TREE(tree) nullptr,
2281 create_anon_label_with_ctx (loc, actor));
2282 add_stmt (b);
2283 b = build_call_expr_internal_loc (loc, IFN_CO_ACTOR, void_type_nodeglobal_trees[TI_VOID_TYPE], 1,
2284 l_num);
2285 b = coro_build_cvt_void_expr_stmt (b, loc);
2286 add_stmt (b);
2287 b = build1 (GOTO_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], CASE_LABEL (rdeflab)(*((const_cast<tree*> (tree_operand_check (((tree_check
((rdeflab), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2287, __FUNCTION__, (CASE_LABEL_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2287, __FUNCTION__)))))
);
2288 add_stmt (b);
2289 lab_num += 2;
2290 }
2291
2292 /* Insert the prototype dispatcher. */
2293 finish_switch_stmt (dispatcher);
2294 finish_else_clause (lsb_if);
2295
2296 finish_if_stmt (lsb_if);
2297
2298 tree r = build_stmt (loc, LABEL_EXPR, actor_begin_label);
2299 add_stmt (r);
2300
2301 /* actor's coroutine 'self handle'. */
2302 tree ash_m = lookup_member (coro_frame_type, coro_self_handle_id, 1,
2303 0, tf_warning_or_error);
2304 tree ash = build_class_member_access_expr (actor_frame, ash_m, NULL_TREE(tree) nullptr,
2305 false, tf_warning_or_error);
2306 /* So construct the self-handle from the frame address. */
2307 tree hfa_m = lookup_member (handle_type, coro_from_address_identifier, 1,
2308 0, tf_warning_or_error);
2309
2310 r = build1 (CONVERT_EXPR, build_pointer_type (void_type_nodeglobal_trees[TI_VOID_TYPE]), actor_fp);
2311 vec<tree, va_gc> *args = make_tree_vector_single (r);
2312 tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE(tree) nullptr, LOOKUP_NORMAL((1 << 0)),
2313 NULLnullptr, tf_warning_or_error);
2314 r = cp_build_init_expr (ash, hfa);
2315 r = coro_build_cvt_void_expr_stmt (r, loc);
2316 add_stmt (r);
2317 release_tree_vector (args);
2318
2319 /* Now we know the real promise, and enough about the frame layout to
2320 decide where to put things. */
2321
2322 await_xform_data xform = {actor, actor_frame};
2323
2324 /* Transform the await expressions in the function body. Only do each
2325 await tree once! */
2326 hash_set<tree> pset;
2327 cp_walk_tree (&fnbody, transform_await_wrapper, &xform, &pset)walk_tree_1 (&fnbody, transform_await_wrapper, &xform
, &pset, cp_walk_subtrees)
;
2328
2329 /* Add in our function body with the co_returns rewritten to final form. */
2330 add_stmt (fnbody);
2331
2332 /* now do the tail of the function. */
2333 r = build_stmt (loc, LABEL_EXPR, del_promise_label);
2334 add_stmt (r);
2335
2336 /* Destructors for the things we built explicitly. */
2337 r = build_special_member_call (promise_proxy, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER], NULLnullptr,
2338 promise_type, LOOKUP_NORMAL((1 << 0)),
2339 tf_warning_or_error);
2340 add_stmt (r);
2341
2342 tree del_frame_label
2343 = create_named_label_with_ctx (loc, "coro.delete.frame", actor);
2344 r = build_stmt (loc, LABEL_EXPR, del_frame_label);
2345 add_stmt (r);
2346
2347 /* Here deallocate the frame (if we allocated it), which we will have at
2348 present. */
2349 tree fnf_m
2350 = lookup_member (coro_frame_type, coro_frame_needs_free_id, 1,
2351 0, tf_warning_or_error);
2352 tree fnf2_x = build_class_member_access_expr (actor_frame, fnf_m, NULL_TREE(tree) nullptr,
2353 false, tf_warning_or_error);
2354
2355 tree need_free_if = begin_if_stmt ();
2356 fnf2_x = build1 (CONVERT_EXPR, integer_type_nodeinteger_types[itk_int], fnf2_x);
2357 tree cmp = build2 (NE_EXPR, integer_type_nodeinteger_types[itk_int], fnf2_x, integer_zero_nodeglobal_trees[TI_INTEGER_ZERO]);
2358 finish_if_stmt_cond (cmp, need_free_if);
2359 if (param_dtor_list != NULLnullptr)
2360 {
2361 int i;
2362 tree pid;
2363 FOR_EACH_VEC_ELT (*param_dtor_list, i, pid)for (i = 0; (*param_dtor_list).iterate ((i), &(pid)); ++(
i))
2364 {
2365 tree m
2366 = lookup_member (coro_frame_type, pid, 1, 0, tf_warning_or_error);
2367 tree a = build_class_member_access_expr (actor_frame, m, NULL_TREE(tree) nullptr,
2368 false, tf_warning_or_error);
2369 tree t = TREE_TYPE (a)((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2369, __FUNCTION__))->typed.type)
;
2370 tree dtor;
2371 dtor
2372 = build_special_member_call (a, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER], NULLnullptr, t,
2373 LOOKUP_NORMAL((1 << 0)), tf_warning_or_error);
2374 add_stmt (dtor);
2375 }
2376 }
2377
2378 /* Build the frame DTOR. */
2379 tree del_coro_fr = coro_get_frame_dtor (actor_fp, orig, frame_size,
2380 promise_type, loc);
2381 finish_expr_stmt (del_coro_fr);
2382 finish_then_clause (need_free_if);
2383 tree scope = IF_SCOPE (need_free_if)(*((const_cast<tree*> (tree_operand_check (((tree_check
((need_free_if), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2383, __FUNCTION__, (IF_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2383, __FUNCTION__)))))
;
2384 IF_SCOPE (need_free_if)(*((const_cast<tree*> (tree_operand_check (((tree_check
((need_free_if), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2384, __FUNCTION__, (IF_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2384, __FUNCTION__)))))
= NULLnullptr;
2385 r = do_poplevel (scope);
2386 add_stmt (r);
2387
2388 /* done. */
2389 r = build_stmt (loc, RETURN_EXPR, NULLnullptr);
2390 suppress_warning (r); /* We don't want a warning about this. */
2391 r = maybe_cleanup_point_expr_void (r);
2392 add_stmt (r);
2393
2394 /* This is the suspend return point. */
2395 r = build_stmt (loc, LABEL_EXPR, ret_label);
2396 add_stmt (r);
2397
2398 r = build_stmt (loc, RETURN_EXPR, NULLnullptr);
2399 suppress_warning (r); /* We don't want a warning about this. */
2400 r = maybe_cleanup_point_expr_void (r);
2401 add_stmt (r);
2402
2403 /* This is the 'continuation' return point. For such a case we have a coro
2404 handle (from the await_suspend() call) and we want handle.resume() to
2405 execute as a tailcall allowing arbitrary chaining of coroutines. */
2406 r = build_stmt (loc, LABEL_EXPR, continue_label);
2407 add_stmt (r);
2408
2409 /* We want to force a tail-call even for O0/1, so this expands the resume
2410 call into its underlying implementation. */
2411 tree addr = lookup_member (void_coro_handle_type, coro_address_identifier,
2412 1, 0, tf_warning_or_error);
2413 addr = build_new_method_call (continuation, addr, NULLnullptr, NULL_TREE(tree) nullptr,
2414 LOOKUP_NORMAL((1 << 0)), NULLnullptr, tf_warning_or_error);
2415 tree resume = build_call_expr_loc
2416 (loc, builtin_decl_explicit (BUILT_IN_CORO_RESUME), 1, addr);
2417
2418 /* In order to support an arbitrary number of coroutine continuations,
2419 we must tail call them. However, some targets do not support indirect
2420 tail calls to arbitrary callees. See PR94359. */
2421 CALL_EXPR_TAILCALL (resume)((tree_check ((resume), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2421, __FUNCTION__, (CALL_EXPR)))->base.addressable_flag
)
= true;
2422 resume = coro_build_cvt_void_expr_stmt (resume, loc);
2423 add_stmt (resume);
2424
2425 r = build_stmt (loc, RETURN_EXPR, NULLnullptr);
2426 gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r)((void)(!(maybe_cleanup_point_expr_void (r) == r) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2426, __FUNCTION__), 0 : 0))
;
2427 add_stmt (r);
2428
2429 /* We've now rewritten the tree and added the initial and final
2430 co_awaits. Now pass over the tree and expand the co_awaits. */
2431
2432 coro_aw_data data = {actor, actor_fp, resume_idx_var, NULL_TREE(tree) nullptr,
2433 ash, del_promise_label, ret_label,
2434 continue_label, continuation, 2};
2435 cp_walk_tree (&actor_body, await_statement_expander, &data, NULL)walk_tree_1 (&actor_body, await_statement_expander, &
data, nullptr, cp_walk_subtrees)
;
2436
2437 BIND_EXPR_BODY (actor_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((actor_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2437, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2437, __FUNCTION__))))))
= pop_stmt_list (actor_body);
2438 TREE_SIDE_EFFECTS (actor_bind)((non_type_check ((actor_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2438, __FUNCTION__))->base.side_effects_flag)
= true;
2439
2440 finish_compound_stmt (stmt);
2441 DECL_SAVED_TREE (actor)((tree_check ((actor), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2441, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
= pop_stmt_list (actor_outer);
2442 verify_stmt_tree (DECL_SAVED_TREE (actor)((tree_check ((actor), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2442, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
);
2443}
2444
2445/* The prototype 'destroy' function :
2446 frame->__Coro_resume_index |= 1;
2447 actor (frame); */
2448
2449static void
2450build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy,
2451 tree actor)
2452{
2453 /* One param, the coro frame pointer. */
2454 tree destr_fp = DECL_ARGUMENTS (destroy)((tree_check ((destroy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2454, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
;
2455
2456 /* We have a definition here. */
2457 TREE_STATIC (destroy)((destroy)->base.static_flag) = 1;
2458
2459 tree destr_outer = push_stmt_list ();
2460 current_stmt_tree ()->stmts_are_full_exprs_p = 1;
2461 tree dstr_stmt = begin_compound_stmt (BCS_FN_BODY);
2462
2463 tree destr_frame = build1 (INDIRECT_REF, coro_frame_type, destr_fp);
2464
2465 tree rat_field = lookup_member (coro_frame_type, coro_resume_index_id,
2466 1, 0, tf_warning_or_error);
2467 tree rat = build3 (COMPONENT_REF, short_unsigned_type_nodeinteger_types[itk_unsigned_short],
2468 destr_frame, rat_field, NULL_TREE(tree) nullptr);
2469
2470 /* _resume_at |= 1 */
2471 tree dstr_idx = build2 (BIT_IOR_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], rat,
2472 build_int_cst (short_unsigned_type_nodeinteger_types[itk_unsigned_short], 1));
2473 tree r = build2 (MODIFY_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], rat, dstr_idx);
2474 r = coro_build_cvt_void_expr_stmt (r, loc);
2475 add_stmt (r);
2476
2477 /* So .. call the actor .. */
2478 r = build_call_expr_loc (loc, actor, 1, destr_fp);
2479 r = coro_build_cvt_void_expr_stmt (r, loc);
2480 add_stmt (r);
2481
2482 /* done. */
2483 r = build_stmt (loc, RETURN_EXPR, NULLnullptr);
2484 r = maybe_cleanup_point_expr_void (r);
2485 add_stmt (r);
2486
2487 finish_compound_stmt (dstr_stmt);
2488 DECL_SAVED_TREE (destroy)((tree_check ((destroy), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2488, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
= pop_stmt_list (destr_outer);
2489}
2490
2491/* Helper that returns an identifier for an appended extension to the
2492 current un-mangled function name. */
2493
2494static tree
2495get_fn_local_identifier (tree orig, const char *append)
2496{
2497 /* Figure out the bits we need to generate names for the outlined things
2498 For consistency, this needs to behave the same way as
2499 ASM_FORMAT_PRIVATE_NAME does. */
2500 tree nm = DECL_NAME (orig)((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2500, __FUNCTION__))->decl_minimal.name)
;
2501 const char *sep, *pfx = "";
2502#ifndef NO_DOT_IN_LABEL
2503 sep = ".";
2504#else
2505#ifndef NO_DOLLAR_IN_LABEL
2506 sep = "$";
2507#else
2508 sep = "_";
2509 pfx = "__";
2510#endif
2511#endif
2512
2513 char *an;
2514 if (DECL_ASSEMBLER_NAME (orig)decl_assembler_name (orig))
2515 an = ACONCAT ((IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (orig)), sep, append,(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(((const char *) (tree_check ((decl_assembler_name (orig)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2515, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0) + 1), concat_copy2 (((const char *
) (tree_check ((decl_assembler_name (orig)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2515, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0))
2516 (char *) 0))(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(((const char *) (tree_check ((decl_assembler_name (orig)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2515, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0) + 1), concat_copy2 (((const char *
) (tree_check ((decl_assembler_name (orig)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2515, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0))
;
2517 else if (DECL_USE_TEMPLATE (orig)(((contains_struct_check ((orig), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2517, __FUNCTION__))->decl_common.lang_specific)->u.base
.use_template)
&& DECL_TEMPLATE_INFO (orig)(((contains_struct_check ((template_info_decl_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2517, __FUNCTION__)), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2517, __FUNCTION__))->decl_common.lang_specific) ->u.
min.template_info)
2518 && DECL_TI_ARGS (orig)((struct tree_template_info*)(tree_check (((((contains_struct_check
((template_info_decl_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2518, __FUNCTION__)), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2518, __FUNCTION__))->decl_common.lang_specific) ->u.
min.template_info)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2518, __FUNCTION__, (TEMPLATE_INFO))))->args
)
2519 {
2520 tree tpl_args = DECL_TI_ARGS (orig)((struct tree_template_info*)(tree_check (((((contains_struct_check
((template_info_decl_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2520, __FUNCTION__)), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2520, __FUNCTION__))->decl_common.lang_specific) ->u.
min.template_info)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2520, __FUNCTION__, (TEMPLATE_INFO))))->args
;
2521 an = ACONCAT ((pfx, IDENTIFIER_POINTER (nm), (char *) 0))(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(pfx, ((const char *) (tree_check ((nm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2521, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), (char *) 0) + 1), concat_copy2 (pfx, ((const char *) (tree_check
((nm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2521, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), (char *) 0))
;
2522 for (int i = 0; i < TREE_VEC_LENGTH (tpl_args)((tree_check ((tpl_args), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2522, __FUNCTION__, (TREE_VEC)))->base.u.length)
; ++i)
2523 {
2524 tree typ = DECL_NAME (TYPE_NAME (TREE_VEC_ELT (tpl_args, i)))((contains_struct_check ((((tree_class_check (((*((const_cast
<tree *> (tree_vec_elt_check ((tpl_args), (i), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2524, __FUNCTION__)))))), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2524, __FUNCTION__))->type_common.name)), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2524, __FUNCTION__))->decl_minimal.name)
;
2525 an = ACONCAT ((an, sep, IDENTIFIER_POINTER (typ), (char *) 0))(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(an, sep, ((const char *) (tree_check ((typ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2525, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), (char *) 0) + 1), concat_copy2 (an, sep, ((const char *) (
tree_check ((typ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2525, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), (char *) 0))
;
2526 }
2527 an = ACONCAT ((an, sep, append, (char *) 0))(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(an, sep, append, (char *) 0) + 1), concat_copy2 (an, sep, append
, (char *) 0))
;
2528 }
2529 else
2530 an = ACONCAT ((pfx, IDENTIFIER_POINTER (nm), sep, append, (char *) 0))(libiberty_concat_ptr = (char *) __builtin_alloca(concat_length
(pfx, ((const char *) (tree_check ((nm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2530, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0) + 1), concat_copy2 (pfx, ((const char
*) (tree_check ((nm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2530, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
), sep, append, (char *) 0))
;
2531
2532 return get_identifier (an)(__builtin_constant_p (an) ? get_identifier_with_length ((an)
, strlen (an)) : get_identifier (an))
;
2533}
2534
2535/* Build an initial or final await initialized from the promise
2536 initial_suspend or final_suspend expression. */
2537
2538static tree
2539build_init_or_final_await (location_t loc, bool is_final)
2540{
2541 tree suspend_alt = is_final ? coro_final_suspend_identifier
2542 : coro_initial_suspend_identifier;
2543
2544 tree setup_call
2545 = coro_build_promise_expression (current_function_decl, NULLnullptr, suspend_alt,
2546 loc, NULLnullptr, /*musthave=*/true);
2547
2548 /* Check for noexcept on the final_suspend call. */
2549 if (flag_exceptionsglobal_options.x_flag_exceptions && is_final && setup_call != error_mark_nodeglobal_trees[TI_ERROR_MARK]
2550 && coro_diagnose_throwing_final_aw_expr (setup_call))
2551 return error_mark_nodeglobal_trees[TI_ERROR_MARK];
2552
2553 /* So build the co_await for this */
2554 /* For initial/final suspends the call is "a" per [expr.await] 3.2. */
2555 return build_co_await (loc, setup_call, (is_final ? FINAL_SUSPEND_POINT
2556 : INITIAL_SUSPEND_POINT));
2557}
2558
2559/* Callback to record the essential data for each await point found in the
2560 function. */
2561
2562static bool
2563register_await_info (tree await_expr, tree aw_type, tree aw_nam)
2564{
2565 bool seen;
2566 suspend_point_info &s
2567 = suspend_points->get_or_insert (await_expr, &seen);
2568 if (seen)
2569 {
2570 warning_at (EXPR_LOCATION (await_expr)((((await_expr)) && ((tree_code_type_tmpl <0>::
tree_code_type[(int) (((enum tree_code) ((await_expr))->base
.code))]) >= tcc_reference && (tree_code_type_tmpl
<0>::tree_code_type[(int) (((enum tree_code) ((await_expr
))->base.code))]) <= tcc_expression)) ? (await_expr)->
exp.locus : ((location_t) 0))
, 0, "duplicate info for %qE",
2571 await_expr);
2572 return false;
2573 }
2574 s.awaitable_type = aw_type;
2575 s.await_field_id = aw_nam;
2576 return true;
2577}
2578
2579/* This data set is used when analyzing statements for await expressions. */
2580
2581struct susp_frame_data
2582{
2583 /* Function-wide. */
2584 tree *field_list; /* The current coroutine frame field list. */
2585 tree handle_type; /* The self-handle type for this coroutine. */
2586 tree fs_label; /* The destination for co_returns. */
2587 vec<tree, va_gc> *block_stack; /* Track block scopes. */
2588 vec<tree, va_gc> *bind_stack; /* Track current bind expr. */
2589 unsigned await_number; /* Which await in the function. */
2590 unsigned cond_number; /* Which replaced condition in the fn. */
2591 /* Temporary values for one statement or expression being analyzed. */
2592 hash_set<tree> captured_temps; /* The suspend captured these temps. */
2593 vec<tree, va_gc> *to_replace; /* The VAR decls to replace. */
2594 hash_set<tree> *truth_aoif_to_expand; /* The set of TRUTH exprs to expand. */
2595 unsigned saw_awaits; /* Count of awaits in this statement */
2596 bool captures_temporary; /* This expr captures temps by ref. */
2597 bool needs_truth_if_exp; /* We must expand a truth_if expression. */
2598 bool has_awaiter_init; /* We must handle initializing an awaiter. */
2599};
2600
2601/* If this is an await expression, then count it (both uniquely within the
2602 function and locally within a single statement). */
2603
2604static tree
2605register_awaits (tree *stmt, int *, void *d)
2606{
2607 tree aw_expr = *stmt;
2608
2609 /* We should have already lowered co_yields to their co_await. */
2610 gcc_checking_assert (TREE_CODE (aw_expr) != CO_YIELD_EXPR)((void)(!(((enum tree_code) (aw_expr)->base.code) != CO_YIELD_EXPR
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2610, __FUNCTION__), 0 : 0))
;
2611
2612 if (TREE_CODE (aw_expr)((enum tree_code) (aw_expr)->base.code) != CO_AWAIT_EXPR)
2613 return NULL_TREE(tree) nullptr;
2614
2615 /* Count how many awaits the current expression contains. */
2616 susp_frame_data *data = (susp_frame_data *) d;
2617 data->saw_awaits++;
2618 /* Each await suspend context is unique, this is a function-wide value. */
2619 data->await_number++;
2620
2621 /* Awaitables should either be user-locals or promoted to coroutine frame
2622 entries at this point, and their initializers should have been broken
2623 out. */
2624 tree aw = TREE_OPERAND (aw_expr, 1)(*((const_cast<tree*> (tree_operand_check ((aw_expr), (
1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2624, __FUNCTION__)))))
;
2625 gcc_checking_assert (!TREE_OPERAND (aw_expr, 2))((void)(!(!(*((const_cast<tree*> (tree_operand_check ((
aw_expr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2625, __FUNCTION__)))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2625, __FUNCTION__), 0 : 0))
;
2626
2627 tree aw_field_type = TREE_TYPE (aw)((contains_struct_check ((aw), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2627, __FUNCTION__))->typed.type)
;
2628 tree aw_field_nam = NULL_TREE(tree) nullptr;
2629 register_await_info (aw_expr, aw_field_type, aw_field_nam);
2630
2631 /* Rewrite target expressions on the await_suspend () to remove extraneous
2632 cleanups for the awaitables, which are now promoted to frame vars and
2633 managed via that. */
2634 tree v = TREE_OPERAND (aw_expr, 3)(*((const_cast<tree*> (tree_operand_check ((aw_expr), (
3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2634, __FUNCTION__)))))
;
2635 tree o = TREE_VEC_ELT (v, 1)(*((const_cast<tree *> (tree_vec_elt_check ((v), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2635, __FUNCTION__)))))
;
2636 if (TREE_CODE (o)((enum tree_code) (o)->base.code) == TARGET_EXPR)
2637 TREE_VEC_ELT (v, 1)(*((const_cast<tree *> (tree_vec_elt_check ((v), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2637, __FUNCTION__)))))
= get_target_expr (TREE_OPERAND (o, 1)(*((const_cast<tree*> (tree_operand_check ((o), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2637, __FUNCTION__)))))
);
2638 return NULL_TREE(tree) nullptr;
2639}
2640
2641/* There are cases where any await expression is relevant. */
2642static tree
2643find_any_await (tree *stmt, int *dosub, void *d)
2644{
2645 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == CO_AWAIT_EXPR)
2646 {
2647 *dosub = 0; /* We don't need to consider this any further. */
2648 tree **p = (tree **) d;
2649 *p = stmt;
2650 return *stmt;
2651 }
2652 return NULL_TREE(tree) nullptr;
2653}
2654
2655static bool
2656tmp_target_expr_p (tree t)
2657{
2658 if (TREE_CODE (t)((enum tree_code) (t)->base.code) != TARGET_EXPR)
2659 return false;
2660 tree v = TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2660, __FUNCTION__)))))
;
2661 if (!DECL_ARTIFICIAL (v)((contains_struct_check ((v), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2661, __FUNCTION__))->decl_common.artificial_flag)
)
2662 return false;
2663 if (DECL_NAME (v)((contains_struct_check ((v), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2663, __FUNCTION__))->decl_minimal.name)
)
2664 return false;
2665 return true;
2666}
2667
2668/* Structure to record sub-expressions that need to be handled by the
2669 statement flattener. */
2670
2671struct coro_interesting_subtree
2672{
2673 tree* entry;
2674 hash_set<tree> *temps_used;
2675};
2676
2677/* tree-walk callback that returns the first encountered sub-expression of
2678 a kind that needs to be handled specifically by the statement flattener. */
2679
2680static tree
2681find_interesting_subtree (tree *expr_p, int *dosub, void *d)
2682{
2683 tree expr = *expr_p;
2684 coro_interesting_subtree *p = (coro_interesting_subtree *)d;
2685 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CO_AWAIT_EXPR)
2686 {
2687 *dosub = 0; /* We don't need to consider this any further. */
2688 if (TREE_OPERAND (expr, 2)(*((const_cast<tree*> (tree_operand_check ((expr), (2),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2688, __FUNCTION__)))))
)
2689 {
2690 p->entry = expr_p;
2691 return expr;
2692 }
2693 }
2694 else if (tmp_target_expr_p (expr)
2695 && !TARGET_EXPR_ELIDING_P (expr)((tree_not_check2 (((tree_check ((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2695, __FUNCTION__, (TARGET_EXPR)))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2695, __FUNCTION__, (TREE_VEC), (SSA_NAME)))->base.u.bits
.lang_flag_3)
2696 && !p->temps_used->contains (expr))
2697 {
2698 p->entry = expr_p;
2699 return expr;
2700 }
2701
2702 return NULL_TREE(tree) nullptr;
2703}
2704
2705/* Node for a doubly-linked list of promoted variables and their
2706 initializers. When the initializer is a conditional expression
2707 the 'then' and 'else' clauses are represented by a linked list
2708 attached to then_cl and else_cl respectively. */
2709
2710struct var_nest_node
2711{
2712 var_nest_node () = default;
2713 var_nest_node (tree v, tree i, var_nest_node *p, var_nest_node *n)
2714 : var(v), init(i), prev(p), next(n), then_cl (NULLnullptr), else_cl (NULLnullptr)
2715 {
2716 if (p)
2717 p->next = this;
2718 if (n)
2719 n->prev = this;
2720 }
2721 tree var;
2722 tree init;
2723 var_nest_node *prev;
2724 var_nest_node *next;
2725 var_nest_node *then_cl;
2726 var_nest_node *else_cl;
2727};
2728
2729/* This is called for single statements from the co-await statement walker.
2730 It checks to see if the statement contains any initializers for awaitables
2731 and if any of these capture items by reference. */
2732
2733static void
2734flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
2735 hash_set<tree> *temps_used, tree *replace_in)
2736{
2737 bool init_expr = false;
2738 switch (TREE_CODE (n->init)((enum tree_code) (n->init)->base.code))
2739 {
2740 default: break;
2741 /* Compound expressions must be flattened specifically. */
2742 case COMPOUND_EXPR:
2743 {
2744 tree first = TREE_OPERAND (n->init, 0)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2744, __FUNCTION__)))))
;
2745 n->init = TREE_OPERAND (n->init, 1)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2745, __FUNCTION__)))))
;
2746 var_nest_node *ins
2747 = new var_nest_node(NULL_TREE(tree) nullptr, first, n->prev, n);
2748 /* The compiler (but not the user) can generate temporaries with
2749 uses in the second arm of a compound expr. */
2750 flatten_await_stmt (ins, promoted, temps_used, &n->init);
2751 flatten_await_stmt (n, promoted, temps_used, NULLnullptr);
2752 /* The two arms have been processed separately. */
2753 return;
2754 }
2755 break;
2756 /* Handle conditional expressions. */
2757 case INIT_EXPR:
2758 init_expr = true;
2759 /* FALLTHROUGH */
2760 case MODIFY_EXPR:
2761 {
2762 tree old_expr = TREE_OPERAND (n->init, 1)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2762, __FUNCTION__)))))
;
2763 if (TREE_CODE (old_expr)((enum tree_code) (old_expr)->base.code) == COMPOUND_EXPR)
2764 {
2765 tree first = TREE_OPERAND (old_expr, 0)(*((const_cast<tree*> (tree_operand_check ((old_expr), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2765, __FUNCTION__)))))
;
2766 TREE_OPERAND (n->init, 1)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2766, __FUNCTION__)))))
= TREE_OPERAND (old_expr, 1)(*((const_cast<tree*> (tree_operand_check ((old_expr), (
1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2766, __FUNCTION__)))))
;
2767 var_nest_node *ins
2768 = new var_nest_node(NULL_TREE(tree) nullptr, first, n->prev, n);
2769 flatten_await_stmt (ins, promoted, temps_used,
2770 &TREE_OPERAND (n->init, 1)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2770, __FUNCTION__)))))
);
2771 flatten_await_stmt (n, promoted, temps_used, NULLnullptr);
2772 return;
2773 }
2774 if (TREE_CODE (old_expr)((enum tree_code) (old_expr)->base.code) != COND_EXPR)
2775 break;
2776 /* Reconstruct x = t ? y : z;
2777 as (void) t ? x = y : x = z; */
2778 tree var = TREE_OPERAND (n->init, 0)(*((const_cast<tree*> (tree_operand_check ((n->init)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2778, __FUNCTION__)))))
;
2779 tree var_type = TREE_TYPE (var)((contains_struct_check ((var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2779, __FUNCTION__))->typed.type)
;
2780 tree cond = COND_EXPR_COND (old_expr)((*((const_cast<tree*> (tree_operand_check (((tree_check
((old_expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2780, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2780, __FUNCTION__))))))
;
2781 /* We are allowed a void type throw in one or both of the cond
2782 expr arms. */
2783 tree then_cl = COND_EXPR_THEN (old_expr)((*((const_cast<tree*> (tree_operand_check (((tree_check
((old_expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2783, __FUNCTION__, (COND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2783, __FUNCTION__))))))
;
2784 if (!VOID_TYPE_P (TREE_TYPE (then_cl))(((enum tree_code) (((contains_struct_check ((then_cl), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2784, __FUNCTION__))->typed.type))->base.code) == VOID_TYPE
)
)
2785 {
2786 gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST)((void)(!(((enum tree_code) (then_cl)->base.code) != STATEMENT_LIST
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2786, __FUNCTION__), 0 : 0))
;
2787 if (init_expr)
2788 then_cl = cp_build_init_expr (var, then_cl);
2789 else
2790 then_cl = build2 (MODIFY_EXPR, var_type, var, then_cl);
2791 }
2792 tree else_cl = COND_EXPR_ELSE (old_expr)((*((const_cast<tree*> (tree_operand_check (((tree_check
((old_expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2792, __FUNCTION__, (COND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2792, __FUNCTION__))))))
;
2793 if (!VOID_TYPE_P (TREE_TYPE (else_cl))(((enum tree_code) (((contains_struct_check ((else_cl), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2793, __FUNCTION__))->typed.type))->base.code) == VOID_TYPE
)
)
2794 {
2795 gcc_checking_assert (TREE_CODE (else_cl) != STATEMENT_LIST)((void)(!(((enum tree_code) (else_cl)->base.code) != STATEMENT_LIST
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2795, __FUNCTION__), 0 : 0))
;
2796 if (init_expr)
2797 else_cl = cp_build_init_expr (var, else_cl);
2798 else
2799 else_cl = build2 (MODIFY_EXPR, var_type, var, else_cl);
2800 }
2801 n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl);
2802 }
2803 /* FALLTHROUGH */
2804 case COND_EXPR:
2805 {
2806 tree *found;
2807 tree cond = COND_EXPR_COND (n->init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((n->init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2807, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2807, __FUNCTION__))))))
;
2808 /* If the condition contains an await expression, then we need to
2809 set that first and use a separate var. */
2810 if (cp_walk_tree (&cond, find_any_await, &found, NULL)walk_tree_1 (&cond, find_any_await, &found, nullptr, cp_walk_subtrees
)
)
2811 {
2812 tree cond_type = TREE_TYPE (cond)((contains_struct_check ((cond), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2812, __FUNCTION__))->typed.type)
;
2813 tree cond_var = build_lang_decl (VAR_DECL, NULL_TREE(tree) nullptr, cond_type);
2814 DECL_ARTIFICIAL (cond_var)((contains_struct_check ((cond_var), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2814, __FUNCTION__))->decl_common.artificial_flag)
= true;
2815 layout_decl (cond_var, 0);
2816 gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type))((void)(!(!((tree_class_check ((cond_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2816, __FUNCTION__))->type_common.needs_constructing_flag
)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2816, __FUNCTION__), 0 : 0))
;
2817 cond = cp_build_init_expr (cond_var, cond);
2818 var_nest_node *ins
2819 = new var_nest_node (cond_var, cond, n->prev, n);
2820 COND_EXPR_COND (n->init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((n->init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2820, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2820, __FUNCTION__))))))
= cond_var;
2821 flatten_await_stmt (ins, promoted, temps_used, NULLnullptr);
2822 }
2823
2824 n->then_cl
2825 = new var_nest_node (n->var, COND_EXPR_THEN (n->init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((n->init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2825, __FUNCTION__, (COND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2825, __FUNCTION__))))))
, NULLnullptr, NULLnullptr);
2826 n->else_cl
2827 = new var_nest_node (n->var, COND_EXPR_ELSE (n->init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((n->init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2827, __FUNCTION__, (COND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2827, __FUNCTION__))))))
, NULLnullptr, NULLnullptr);
2828 flatten_await_stmt (n->then_cl, promoted, temps_used, NULLnullptr);
2829 /* Point to the start of the flattened code. */
2830 while (n->then_cl->prev)
2831 n->then_cl = n->then_cl->prev;
2832 flatten_await_stmt (n->else_cl, promoted, temps_used, NULLnullptr);
2833 while (n->else_cl->prev)
2834 n->else_cl = n->else_cl->prev;
2835 return;
2836 }
2837 break;
2838 }
2839 coro_interesting_subtree v = { NULLnullptr, temps_used };
2840 tree t = cp_walk_tree (&n->init, find_interesting_subtree, (void *)&v, NULL)walk_tree_1 (&n->init, find_interesting_subtree, (void
*)&v, nullptr, cp_walk_subtrees)
;
2841 if (!t)
2842 return;
2843 switch (TREE_CODE (t)((enum tree_code) (t)->base.code))
2844 {
2845 default: break;
2846 case CO_AWAIT_EXPR:
2847 {
2848 /* Await expressions with initializers have a compiler-temporary
2849 as the awaitable. 'promote' this. */
2850 tree var = TREE_OPERAND (t, 1)(*((const_cast<tree*> (tree_operand_check ((t), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2850, __FUNCTION__)))))
;
2851 bool already_present = promoted->add (var);
2852 gcc_checking_assert (!already_present)((void)(!(!already_present) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2852, __FUNCTION__), 0 : 0))
;
2853 tree init = TREE_OPERAND (t, 2)(*((const_cast<tree*> (tree_operand_check ((t), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2853, __FUNCTION__)))))
;
2854 switch (TREE_CODE (init)((enum tree_code) (init)->base.code))
2855 {
2856 default: break;
2857 case INIT_EXPR:
2858 case MODIFY_EXPR:
2859 {
2860 tree inner = TREE_OPERAND (init, 1)(*((const_cast<tree*> (tree_operand_check ((init), (1),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2860, __FUNCTION__)))))
;
2861 /* We can have non-lvalue-expressions here, but when we see
2862 a target expression, mark it as already used. */
2863 if (TREE_CODE (inner)((enum tree_code) (inner)->base.code) == TARGET_EXPR)
2864 {
2865 temps_used->add (inner);
2866 gcc_checking_assert((void)(!(((enum tree_code) ((*((const_cast<tree*> (tree_operand_check
((inner), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2867, __FUNCTION__))))))->base.code) != COND_EXPR) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2867, __FUNCTION__), 0 : 0))
2867 (TREE_CODE (TREE_OPERAND (inner, 1)) != COND_EXPR)((void)(!(((enum tree_code) ((*((const_cast<tree*> (tree_operand_check
((inner), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2867, __FUNCTION__))))))->base.code) != COND_EXPR) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2867, __FUNCTION__), 0 : 0))
;
2868 }
2869 }
2870 break;
2871 case CALL_EXPR:
2872 /* If this is a call and not a CTOR, then we didn't expect it. */
2873 gcc_checking_assert((void)(!(((tree_check (((((enum tree_code) ((*((const_cast<
tree*> (tree_operand_check (((*((const_cast<tree*> (
tree_operand_check (((tree_check ((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__))))))->base.code) == TEMPLATE_DECL ? (
(struct tree_template_decl *)(const_cast<union tree_node *
> ((((tree_check (((*((const_cast<tree*> (tree_operand_check
(((*((const_cast<tree*> (tree_operand_check (((tree_check
((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (*(
(const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__))))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_constructor
)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__), 0 : 0))
2874 (DECL_CONSTRUCTOR_P (TREE_OPERAND (CALL_EXPR_FN (init), 0)))((void)(!(((tree_check (((((enum tree_code) ((*((const_cast<
tree*> (tree_operand_check (((*((const_cast<tree*> (
tree_operand_check (((tree_check ((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__))))))->base.code) == TEMPLATE_DECL ? (
(struct tree_template_decl *)(const_cast<union tree_node *
> ((((tree_check (((*((const_cast<tree*> (tree_operand_check
(((*((const_cast<tree*> (tree_operand_check (((tree_check
((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (*(
(const_cast<tree*> (tree_operand_check (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (CALL_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__))))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_constructor
)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2874, __FUNCTION__), 0 : 0))
;
2875 break;
2876 }
2877 var_nest_node *ins = new var_nest_node (var, init, n->prev, n);
2878 TREE_OPERAND (t, 2)(*((const_cast<tree*> (tree_operand_check ((t), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2878, __FUNCTION__)))))
= NULL_TREE(tree) nullptr;
2879 flatten_await_stmt (ins, promoted, temps_used, NULLnullptr);
2880 flatten_await_stmt (n, promoted, temps_used, NULLnullptr);
2881 return;
2882 }
2883 break;
2884 case TARGET_EXPR:
2885 {
2886 /* We have a temporary; promote it, but allow for the idiom in code
2887 generated by the compiler like
2888 a = (target_expr produces temp, op uses temp). */
2889 tree init = t;
2890 temps_used->add (init);
2891 tree var_type = TREE_TYPE (init)((contains_struct_check ((init), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2891, __FUNCTION__))->typed.type)
;
2892 char *buf = xasprintf ("D.%d", DECL_UID (TREE_OPERAND (init, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check
((init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2892, __FUNCTION__)))))), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2892, __FUNCTION__))->decl_minimal.uid)
);
2893 tree var = build_lang_decl (VAR_DECL, get_identifier (buf)(__builtin_constant_p (buf) ? get_identifier_with_length ((buf
), strlen (buf)) : get_identifier (buf))
, var_type);
2894 DECL_ARTIFICIAL (var)((contains_struct_check ((var), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2894, __FUNCTION__))->decl_common.artificial_flag)
= true;
2895 free (buf);
2896 bool already_present = promoted->add (var);
2897 gcc_checking_assert (!already_present)((void)(!(!already_present) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2897, __FUNCTION__), 0 : 0))
;
2898 tree inner = TREE_OPERAND (init, 1)(*((const_cast<tree*> (tree_operand_check ((init), (1),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2898, __FUNCTION__)))))
;
2899 gcc_checking_assert (TREE_CODE (inner) != COND_EXPR)((void)(!(((enum tree_code) (inner)->base.code) != COND_EXPR
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2899, __FUNCTION__), 0 : 0))
;
2900 init = cp_build_modify_expr (input_location, var, INIT_EXPR, init,
2901 tf_warning_or_error);
2902 /* Simplify for the case that we have an init containing the temp
2903 alone. */
2904 if (t == n->init && n->var == NULL_TREE(tree) nullptr)
2905 {
2906 n->var = var;
2907 proxy_replace pr = {TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2907, __FUNCTION__)))))
, var};
2908 cp_walk_tree (&init, replace_proxy, &pr, NULL)walk_tree_1 (&init, replace_proxy, &pr, nullptr, cp_walk_subtrees
)
;
2909 n->init = init;
2910 if (replace_in)
2911 cp_walk_tree (replace_in, replace_proxy, &pr, NULL)walk_tree_1 (replace_in, replace_proxy, &pr, nullptr, cp_walk_subtrees
)
;
2912 flatten_await_stmt (n, promoted, temps_used, NULLnullptr);
2913 }
2914 else
2915 {
2916 var_nest_node *ins
2917 = new var_nest_node (var, init, n->prev, n);
2918 /* We have to replace the target expr... */
2919 *v.entry = var;
2920 /* ... and any uses of its var. */
2921 proxy_replace pr = {TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2921, __FUNCTION__)))))
, var};
2922 cp_walk_tree (&n->init, replace_proxy, &pr, NULL)walk_tree_1 (&n->init, replace_proxy, &pr, nullptr
, cp_walk_subtrees)
;
2923 /* Compiler-generated temporaries can also have uses in
2924 following arms of compound expressions, which will be listed
2925 in 'replace_in' if present. */
2926 if (replace_in)
2927 cp_walk_tree (replace_in, replace_proxy, &pr, NULL)walk_tree_1 (replace_in, replace_proxy, &pr, nullptr, cp_walk_subtrees
)
;
2928 flatten_await_stmt (ins, promoted, temps_used, NULLnullptr);
2929 flatten_await_stmt (n, promoted, temps_used, NULLnullptr);
2930 }
2931 return;
2932 }
2933 break;
2934 }
2935}
2936
2937/* Helper for 'process_conditional' that handles recursion into nested
2938 conditionals. */
2939
2940static void
2941handle_nested_conditionals (var_nest_node *n, vec<tree>& list,
2942 hash_map<tree, tree>& map)
2943{
2944 do
2945 {
2946 if (n->var && DECL_NAME (n->var)((contains_struct_check ((n->var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2946, __FUNCTION__))->decl_minimal.name)
)
2947 {
2948 list.safe_push (n->var);
2949 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (n->var))(((tree_class_check ((((contains_struct_check ((n->var), (
TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2949, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2949, __FUNCTION__))->type_common.lang_flag_4))
)
2950 {
2951 bool existed;
2952 tree& flag = map.get_or_insert (n->var, &existed);
2953 if (!existed)
2954 {
2955 /* We didn't see this var before and it needs a DTOR, so
2956 build a guard variable for it. */
2957 char *nam
2958 = xasprintf ("%s_guard",
2959 IDENTIFIER_POINTER (DECL_NAME (n->var))((const char *) (tree_check ((((contains_struct_check ((n->
var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2959, __FUNCTION__))->decl_minimal.name)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2959, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
)
);
2960 flag = build_lang_decl (VAR_DECL, get_identifier (nam)(__builtin_constant_p (nam) ? get_identifier_with_length ((nam
), strlen (nam)) : get_identifier (nam))
,
2961 boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE]);
2962 free (nam);
2963 DECL_ARTIFICIAL (flag)((contains_struct_check ((flag), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2963, __FUNCTION__))->decl_common.artificial_flag)
= true;
2964 }
2965
2966 /* The initializer for this variable is replaced by a compound
2967 expression that performs the init and then records that the
2968 variable is live (and the DTOR should be run at the scope
2969 exit. */
2970 tree set_flag = cp_build_init_expr (flag, boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE]);
2971 n->init
2972 = build2 (COMPOUND_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], n->init, set_flag);
2973 }
2974 }
2975 if (TREE_CODE (n->init)((enum tree_code) (n->init)->base.code) == COND_EXPR)
2976 {
2977 tree new_then = push_stmt_list ();
2978 handle_nested_conditionals (n->then_cl, list, map);
2979 new_then = pop_stmt_list (new_then);
2980 tree new_else = push_stmt_list ();
2981 handle_nested_conditionals (n->else_cl, list, map);
2982 new_else = pop_stmt_list (new_else);
2983 tree new_if
2984 = build4 (IF_STMT, void_type_nodeglobal_trees[TI_VOID_TYPE], COND_EXPR_COND (n->init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((n->init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2984, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 2984, __FUNCTION__))))))
,
2985 new_then, new_else, NULL_TREE(tree) nullptr);
2986 add_stmt (new_if);
2987 }
2988 else
2989 finish_expr_stmt (n->init);
2990 n = n->next;
2991 } while (n);
2992}
2993
2994/* helper for 'maybe_promote_temps'.
2995
2996 When we have a conditional expression which might embed await expressions
2997 and/or promoted variables, we need to handle it appropriately.
2998
2999 The linked lists for the 'then' and 'else' clauses in a conditional node
3000 identify the promoted variables (but these cannot be wrapped in a regular
3001 cleanup).
3002
3003 So recurse through the lists and build up a composite list of captured vars.
3004 Declare these and any guard variables needed to decide if a DTOR should be
3005 run. Then embed the conditional into a try-finally expression that handles
3006 running each DTOR conditionally on its guard variable. */
3007
3008static void
3009process_conditional (var_nest_node *n, tree& vlist)
3010{
3011 tree init = n->init;
3012 hash_map<tree, tree> var_flags;
3013 auto_vec<tree> var_list;
3014 tree new_then = push_stmt_list ();
3015 handle_nested_conditionals (n->then_cl, var_list, var_flags);
3016 new_then = pop_stmt_list (new_then);
3017 tree new_else = push_stmt_list ();
3018 handle_nested_conditionals (n->else_cl, var_list, var_flags);
3019 new_else = pop_stmt_list (new_else);
3020 /* Declare the vars. There are two loops so that the boolean flags are
3021 grouped in the frame. */
3022 for (unsigned i = 0; i < var_list.length(); i++)
3023 {
3024 tree var = var_list[i];
3025 DECL_CHAIN (var)(((contains_struct_check (((contains_struct_check ((var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3025, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3025, __FUNCTION__))->common.chain))
= vlist;
3026 vlist = var;
3027 add_decl_expr (var);
3028 }
3029 /* Define the guard flags for variables that need a DTOR. */
3030 for (unsigned i = 0; i < var_list.length(); i++)
3031 {
3032 tree *flag = var_flags.get (var_list[i]);
3033 if (flag)
3034 {
3035 DECL_INITIAL (*flag)((contains_struct_check ((*flag), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3035, __FUNCTION__))->decl_common.initial)
= boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE];
3036 DECL_CHAIN (*flag)(((contains_struct_check (((contains_struct_check ((*flag), (
TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3036, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3036, __FUNCTION__))->common.chain))
= vlist;
3037 vlist = *flag;
3038 add_decl_expr (*flag);
3039 }
3040 }
3041 tree new_if
3042 = build4 (IF_STMT, void_type_nodeglobal_trees[TI_VOID_TYPE], COND_EXPR_COND (init)((*((const_cast<tree*> (tree_operand_check (((tree_check
((init), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3042, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3042, __FUNCTION__))))))
,
3043 new_then, new_else, NULL_TREE(tree) nullptr);
3044 /* Build a set of conditional DTORs. */
3045 tree final_actions = push_stmt_list ();
3046 while (!var_list.is_empty())
3047 {
3048 tree var = var_list.pop ();
3049 tree *flag = var_flags.get (var);
3050 if (!flag)
3051 continue;
3052 tree var_type = TREE_TYPE (var)((contains_struct_check ((var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3052, __FUNCTION__))->typed.type)
;
3053 tree cleanup
3054 = build_special_member_call (var, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
3055 NULLnullptr, var_type, LOOKUP_NORMAL((1 << 0)),
3056 tf_warning_or_error);
3057 tree cond_cleanup = begin_if_stmt ();
3058 finish_if_stmt_cond (*flag, cond_cleanup);
3059 finish_expr_stmt (cleanup);
3060 finish_then_clause (cond_cleanup);
3061 finish_if_stmt (cond_cleanup);
3062 }
3063 final_actions = pop_stmt_list (final_actions);
3064 tree try_finally
3065 = build2 (TRY_FINALLY_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], new_if, final_actions);
3066 add_stmt (try_finally);
3067}
3068
3069/* Given *STMT, that contains at least one await expression.
3070
3071 The full expression represented in the original source code will contain
3072 suspension points, but it is still required that the lifetime of temporary
3073 values extends to the end of the expression.
3074
3075 We already have a mechanism to 'promote' user-authored local variables
3076 to a coroutine frame counterpart (which allows explicit management of the
3077 lifetime across suspensions). The transform here re-writes STMT into
3078 a bind expression, promotes temporary values into local variables in that
3079 and flattens the statement into a series of cleanups.
3080
3081 Conditional expressions are re-written to regular 'if' statements.
3082 The cleanups for variables initialized inside a conditional (including
3083 nested cases) are wrapped in a try-finally clause, with guard variables
3084 to determine which DTORs need to be run. */
3085
3086static tree
3087maybe_promote_temps (tree *stmt, void *d)
3088{
3089 susp_frame_data *awpts = (susp_frame_data *) d;
3090
3091 location_t sloc = EXPR_LOCATION (*stmt)((((*stmt)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((*stmt))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((*stmt))->base.code))]) <= tcc_expression
)) ? (*stmt)->exp.locus : ((location_t) 0))
;
3092 tree expr = *stmt;
3093 /* Strip off uninteresting wrappers. */
3094 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CLEANUP_POINT_EXPR)
3095 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3095, __FUNCTION__)))))
;
3096 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == EXPR_STMT)
3097 expr = EXPR_STMT_EXPR (expr)(*((const_cast<tree*> (tree_operand_check (((tree_check
((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3097, __FUNCTION__, (EXPR_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3097, __FUNCTION__)))))
;
3098 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CONVERT_EXPR
3099 && VOID_TYPE_P (TREE_TYPE (expr))(((enum tree_code) (((contains_struct_check ((expr), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3099, __FUNCTION__))->typed.type))->base.code) == VOID_TYPE
)
)
3100 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3100, __FUNCTION__)))))
;
3101 STRIP_NOPS (expr)(expr) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((expr)))))
;
3102
3103 /* We walk the statement trees, flattening it into an ordered list of
3104 variables with initializers and fragments corresponding to compound
3105 expressions, truth or/and if and ternary conditionals. Conditional
3106 expressions carry a nested list of fragments for the then and else
3107 clauses. We anchor to the 'bottom' of the fragment list; we will write
3108 a cleanup nest with one shell for each variable initialized. */
3109 var_nest_node *root = new var_nest_node (NULL_TREE(tree) nullptr, expr, NULLnullptr, NULLnullptr);
3110 /* Check to see we didn't promote one twice. */
3111 hash_set<tree> promoted_vars;
3112 hash_set<tree> used_temps;
3113 flatten_await_stmt (root, &promoted_vars, &used_temps, NULLnullptr);
3114
3115 gcc_checking_assert (root->next == NULL)((void)(!(root->next == nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3115, __FUNCTION__), 0 : 0))
;
3116 tree vlist = NULL_TREE(tree) nullptr;
3117 var_nest_node *t = root;
3118 /* We build the bind scope expression from the bottom-up.
3119 EXPR_LIST holds the inner expression nest at the current cleanup
3120 level (becoming the final expression list when we've exhausted the
3121 number of sub-expression fragments). */
3122 tree expr_list = NULL_TREE(tree) nullptr;
3123 do
3124 {
3125 tree new_list = push_stmt_list ();
3126 /* When we have a promoted variable, then add that to the bind scope
3127 and initialize it. When there's no promoted variable, we just need
3128 to run the initializer.
3129 If the initializer is a conditional expression, we need to collect
3130 and declare any promoted variables nested within it. DTORs for such
3131 variables must be run conditionally too. */
3132 if (t->var)
3133 {
3134 tree var = t->var;
3135 DECL_CHAIN (var)(((contains_struct_check (((contains_struct_check ((var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3135, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3135, __FUNCTION__))->common.chain))
= vlist;
3136 vlist = var;
3137 add_decl_expr (var);
3138 if (TREE_CODE (t->init)((enum tree_code) (t->init)->base.code) == COND_EXPR)
3139 process_conditional (t, vlist);
3140 else
3141 finish_expr_stmt (t->init);
3142 tree var_type = TREE_TYPE (var)((contains_struct_check ((var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3142, __FUNCTION__))->typed.type)
;
3143 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (var_type)(((tree_class_check ((var_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3143, __FUNCTION__))->type_common.lang_flag_4))
)
3144 {
3145 tree cleanup
3146 = build_special_member_call (var, complete_dtor_identifiercp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER],
3147 NULLnullptr, var_type, LOOKUP_NORMAL((1 << 0)),
3148 tf_warning_or_error);
3149 tree cl = build_stmt (sloc, CLEANUP_STMT, expr_list, cleanup, var);
3150 add_stmt (cl); /* push this onto the level above. */
3151 }
3152 else if (expr_list)
3153 {
3154 if (TREE_CODE (expr_list)((enum tree_code) (expr_list)->base.code) != STATEMENT_LIST)
3155 add_stmt (expr_list);
3156 else if (!tsi_end_p (tsi_start (expr_list)))
3157 add_stmt (expr_list);
3158 }
3159 }
3160 else
3161 {
3162 if (TREE_CODE (t->init)((enum tree_code) (t->init)->base.code) == COND_EXPR)
3163 process_conditional (t, vlist);
3164 else
3165 finish_expr_stmt (t->init);
3166 if (expr_list)
3167 {
3168 if (TREE_CODE (expr_list)((enum tree_code) (expr_list)->base.code) != STATEMENT_LIST)
3169 add_stmt (expr_list);
3170 else if (!tsi_end_p (tsi_start (expr_list)))
3171 add_stmt (expr_list);
3172 }
3173 }
3174 expr_list = pop_stmt_list (new_list);
3175 var_nest_node *old = t;
3176 t = t->prev;
3177 delete old;
3178 } while (t);
3179
3180 /* Now produce the bind expression containing the 'promoted' temporaries
3181 as its variable list, and the cleanup nest as the statement. */
3182 tree await_bind = build3_loc (sloc, BIND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE],
3183 NULLnullptr, NULLnullptr, NULLnullptr);
3184 BIND_EXPR_BODY (await_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3184, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3184, __FUNCTION__))))))
= expr_list;
3185 BIND_EXPR_VARS (await_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3185, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3185, __FUNCTION__))))))
= nreverse (vlist);
3186 tree b_block = make_node (BLOCK);
3187 if (!awpts->block_stack->is_empty ())
3188 {
3189 tree s_block = awpts->block_stack->last ();
3190 if (s_block)
3191 {
3192 BLOCK_SUPERCONTEXT (b_block)((tree_check ((b_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3192, __FUNCTION__, (BLOCK)))->block.supercontext)
= s_block;
3193 BLOCK_CHAIN (b_block)((tree_check ((b_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3193, __FUNCTION__, (BLOCK)))->block.chain)
= BLOCK_SUBBLOCKS (s_block)((tree_check ((s_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3193, __FUNCTION__, (BLOCK)))->block.subblocks)
;
3194 BLOCK_SUBBLOCKS (s_block)((tree_check ((s_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3194, __FUNCTION__, (BLOCK)))->block.subblocks)
= b_block;
3195 }
3196 }
3197 BLOCK_VARS (b_block)((tree_check ((b_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3197, __FUNCTION__, (BLOCK)))->block.vars)
= BIND_EXPR_VARS (await_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3197, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3197, __FUNCTION__))))))
;
3198 BIND_EXPR_BLOCK (await_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3198, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3198, __FUNCTION__))))))
= b_block;
3199 TREE_SIDE_EFFECTS (await_bind)((non_type_check ((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3199, __FUNCTION__))->base.side_effects_flag)
= TREE_SIDE_EFFECTS (BIND_EXPR_BODY (await_bind))((non_type_check ((((*((const_cast<tree*> (tree_operand_check
(((tree_check ((await_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3199, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3199, __FUNCTION__))))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3199, __FUNCTION__))->base.side_effects_flag)
;
3200 *stmt = await_bind;
3201 hash_set<tree> visited;
3202 return cp_walk_tree (stmt, register_awaits, d, &visited)walk_tree_1 (stmt, register_awaits, d, &visited, cp_walk_subtrees
)
;
3203}
3204
3205/* Lightweight callback to determine two key factors:
3206 1) If the statement/expression contains any await expressions.
3207 2) If the statement/expression potentially requires a re-write to handle
3208 TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion
3209 so that the await expressions are not processed in the case of the
3210 short-circuit arm.
3211
3212 CO_YIELD expressions are re-written to their underlying co_await. */
3213
3214static tree
3215analyze_expression_awaits (tree *stmt, int *do_subtree, void *d)
3216{
3217 susp_frame_data *awpts = (susp_frame_data *) d;
3218
3219 switch (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code))
3220 {
3221 default: return NULL_TREE(tree) nullptr;
3222 case CO_YIELD_EXPR:
3223 /* co_yield is syntactic sugar, re-write it to co_await. */
3224 *stmt = TREE_OPERAND (*stmt, 1)(*((const_cast<tree*> (tree_operand_check ((*stmt), (1)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3224, __FUNCTION__)))))
;
3225 /* FALLTHROUGH */
3226 case CO_AWAIT_EXPR:
3227 awpts->saw_awaits++;
3228 /* A non-null initializer for the awaiter means we need to expand. */
3229 if (TREE_OPERAND (*stmt, 2)(*((const_cast<tree*> (tree_operand_check ((*stmt), (2)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3229, __FUNCTION__)))))
)
3230 awpts->has_awaiter_init = true;
3231 break;
3232 case TRUTH_ANDIF_EXPR:
3233 case TRUTH_ORIF_EXPR:
3234 {
3235 /* We don't need special action for awaits in the always-executed
3236 arm of a TRUTH_IF. */
3237 if (tree res = cp_walk_tree (&TREE_OPERAND (*stmt, 0),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
((*stmt), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3237, __FUNCTION__))))), analyze_expression_awaits, d, nullptr
, cp_walk_subtrees)
3238 analyze_expression_awaits, d, NULL)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
((*stmt), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3237, __FUNCTION__))))), analyze_expression_awaits, d, nullptr
, cp_walk_subtrees)
)
3239 return res;
3240 /* However, if there are await expressions on the conditionally
3241 executed branch, we must expand the TRUTH_IF to ensure that the
3242 expanded await expression control-flow is fully contained in the
3243 conditionally executed code. */
3244 unsigned aw_count = awpts->saw_awaits;
3245 if (tree res = cp_walk_tree (&TREE_OPERAND (*stmt, 1),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
((*stmt), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3245, __FUNCTION__))))), analyze_expression_awaits, d, nullptr
, cp_walk_subtrees)
3246 analyze_expression_awaits, d, NULL)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
((*stmt), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3245, __FUNCTION__))))), analyze_expression_awaits, d, nullptr
, cp_walk_subtrees)
)
3247 return res;
3248 if (awpts->saw_awaits > aw_count)
3249 {
3250 awpts->truth_aoif_to_expand->add (*stmt);
3251 awpts->needs_truth_if_exp = true;
3252 }
3253 /* We've done the sub-trees here. */
3254 *do_subtree = 0;
3255 }
3256 break;
3257 }
3258
3259 return NULL_TREE(tree) nullptr; /* Recurse until done. */
3260}
3261
3262/* Given *EXPR
3263 If EXPR contains a TRUTH_{AND,OR}IF_EXPR, TAOIE with an await expr on
3264 the conditionally executed branch, change this in a ternary operator.
3265
3266 bool not_expr = TAOIE == TRUTH_ORIF_EXPR ? NOT : NOP;
3267 not_expr (always-exec expr) ? conditionally-exec expr : not_expr;
3268
3269 Apply this recursively to the condition and the conditionally-exec
3270 branch. */
3271
3272struct truth_if_transform {
3273 tree *orig_stmt;
3274 tree scratch_var;
3275 hash_set<tree> *truth_aoif_to_expand;
3276};
3277
3278static tree
3279expand_one_truth_if (tree *expr, int *do_subtree, void *d)
3280{
3281 truth_if_transform *xform = (truth_if_transform *) d;
3282
3283 bool needs_not = false;
3284 switch (TREE_CODE (*expr)((enum tree_code) (*expr)->base.code))
3285 {
3286 default: break;
3287 case TRUTH_ORIF_EXPR:
3288 needs_not = true;
3289 /* FALLTHROUGH */
3290 case TRUTH_ANDIF_EXPR:
3291 {
3292 if (!xform->truth_aoif_to_expand->contains (*expr))
3293 break;
3294
3295 location_t sloc = EXPR_LOCATION (*expr)((((*expr)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((*expr))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((*expr))->base.code))]) <= tcc_expression
)) ? (*expr)->exp.locus : ((location_t) 0))
;
3296 /* Transform truth expression into a cond expression with
3297 * the always-executed arm as the condition.
3298 * the conditionally-executed arm as the then clause.
3299 * the 'else' clause is fixed: 'true' for ||,'false' for &&. */
3300 tree cond = TREE_OPERAND (*expr, 0)(*((const_cast<tree*> (tree_operand_check ((*expr), (0)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3300, __FUNCTION__)))))
;
3301 tree test1 = TREE_OPERAND (*expr, 1)(*((const_cast<tree*> (tree_operand_check ((*expr), (1)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3301, __FUNCTION__)))))
;
3302 tree fixed = needs_not ? boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE] : boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE];
3303 if (needs_not)
3304 cond = build1 (TRUTH_NOT_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], cond);
3305 tree cond_expr
3306 = build3_loc (sloc, COND_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE],
3307 cond, test1, fixed);
3308 *expr = cond_expr;
3309 if (tree res = cp_walk_tree (&COND_EXPR_COND (*expr),walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3309, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3309, __FUNCTION__)))))), expand_one_truth_if, d, nullptr, cp_walk_subtrees
)
3310 expand_one_truth_if, d, NULL)walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3309, __FUNCTION__, (COND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3309, __FUNCTION__)))))), expand_one_truth_if, d, nullptr, cp_walk_subtrees
)
)
3311 return res;
3312 if (tree res = cp_walk_tree (&COND_EXPR_THEN (*expr),walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3312, __FUNCTION__, (COND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3312, __FUNCTION__)))))), expand_one_truth_if, d, nullptr, cp_walk_subtrees
)
3313 expand_one_truth_if, d, NULL)walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3312, __FUNCTION__, (COND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3312, __FUNCTION__)))))), expand_one_truth_if, d, nullptr, cp_walk_subtrees
)
)
3314 return res;
3315 /* We've manually processed necessary sub-trees here. */
3316 *do_subtree = 0;
3317 }
3318 break;
3319 }
3320 return NULL_TREE(tree) nullptr;
3321}
3322
3323/* Helper that adds a new variable of VAR_TYPE to a bind scope BIND, the
3324 name is made up from NAM_ROOT, NAM_VERS. */
3325
3326static tree
3327add_var_to_bind (tree& bind, tree var_type,
3328 const char *nam_root, unsigned nam_vers)
3329{
3330 tree b_vars = BIND_EXPR_VARS (bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3330, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3330, __FUNCTION__))))))
;
3331 /* Build a variable to hold the condition, this will be included in the
3332 frame as a local var. */
3333 char *nam = xasprintf ("__%s_%d", nam_root, nam_vers);
3334 tree newvar = build_lang_decl (VAR_DECL, get_identifier (nam)(__builtin_constant_p (nam) ? get_identifier_with_length ((nam
), strlen (nam)) : get_identifier (nam))
, var_type);
3335 free (nam);
3336 DECL_CHAIN (newvar)(((contains_struct_check (((contains_struct_check ((newvar), (
TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3336, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3336, __FUNCTION__))->common.chain))
= b_vars;
3337 BIND_EXPR_VARS (bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3337, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3337, __FUNCTION__))))))
= newvar;
3338 return newvar;
3339}
3340
3341/* Helper to build and add if (!cond) break; */
3342
3343static void
3344coro_build_add_if_not_cond_break (tree cond)
3345{
3346 tree if_stmt = begin_if_stmt ();
3347 tree invert = build1 (TRUTH_NOT_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], cond);
3348 finish_if_stmt_cond (invert, if_stmt);
3349 finish_break_stmt ();
3350 finish_then_clause (if_stmt);
3351 finish_if_stmt (if_stmt);
3352}
3353
3354/* Tree walk callback to replace continue statements with goto label. */
3355static tree
3356replace_continue (tree *stmt, int *do_subtree, void *d)
3357{
3358 tree expr = *stmt;
3359 if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == CLEANUP_POINT_EXPR)
3360 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3360, __FUNCTION__)))))
;
3361 if (CONVERT_EXPR_P (expr)((((enum tree_code) (expr)->base.code)) == NOP_EXPR || (((
enum tree_code) (expr)->base.code)) == CONVERT_EXPR)
&& VOID_TYPE_P (expr)(((enum tree_code) (expr)->base.code) == VOID_TYPE))
3362 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3362, __FUNCTION__)))))
;
3363 STRIP_NOPS (expr)(expr) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((expr)))))
;
3364 if (!STATEMENT_CLASS_P (expr)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code
) (expr)->base.code))] == tcc_statement)
)
3365 return NULL_TREE(tree) nullptr;
3366
3367 switch (TREE_CODE (expr)((enum tree_code) (expr)->base.code))
3368 {
3369 /* Unless it's a special case, just walk the subtrees as usual. */
3370 default: return NULL_TREE(tree) nullptr;
3371
3372 case CONTINUE_STMT:
3373 {
3374 tree *label = (tree *)d;
3375 location_t loc = EXPR_LOCATION (expr)((((expr)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((expr))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((expr))->base.code))]) <= tcc_expression
)) ? (expr)->exp.locus : ((location_t) 0))
;
3376 /* re-write a continue to goto label. */
3377 *stmt = build_stmt (loc, GOTO_EXPR, *label);
3378 *do_subtree = 0;
3379 return NULL_TREE(tree) nullptr;
3380 }
3381
3382 /* Statements that do not require recursion. */
3383 case DECL_EXPR:
3384 case BREAK_STMT:
3385 case GOTO_EXPR:
3386 case LABEL_EXPR:
3387 case CASE_LABEL_EXPR:
3388 case ASM_EXPR:
3389 /* These must break recursion. */
3390 case FOR_STMT:
3391 case WHILE_STMT:
3392 case DO_STMT:
3393 *do_subtree = 0;
3394 return NULL_TREE(tree) nullptr;
3395 }
3396}
3397
3398/* Tree walk callback to analyze, register and pre-process statements that
3399 contain await expressions. */
3400
3401static tree
3402await_statement_walker (tree *stmt, int *do_subtree, void *d)
3403{
3404 tree res = NULL_TREE(tree) nullptr;
3405 susp_frame_data *awpts = (susp_frame_data *) d;
3406
3407 /* Process a statement at a time. */
3408 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == BIND_EXPR)
3409 {
3410 /* For conditional expressions, we might wish to add an artificial var
3411 to their containing bind expr. */
3412 vec_safe_push (awpts->bind_stack, *stmt);
3413 /* We might need to insert a new bind expression, and want to link it
3414 into the correct scope, so keep a note of the current block scope. */
3415 tree blk = BIND_EXPR_BLOCK (*stmt)((*((const_cast<tree*> (tree_operand_check (((tree_check
((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3415, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3415, __FUNCTION__))))))
;
3416 vec_safe_push (awpts->block_stack, blk);
3417 res = cp_walk_tree (&BIND_EXPR_BODY (*stmt), await_statement_walker,walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3417, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3417, __FUNCTION__)))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
3418 d, NULL)walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3417, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3417, __FUNCTION__)))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
;
3419 awpts->block_stack->pop ();
3420 awpts->bind_stack->pop ();
3421 *do_subtree = 0; /* Done subtrees. */
3422 return res;
3423 }
3424 else if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == STATEMENT_LIST)
3425 {
3426 for (tree &s : tsi_range (*stmt))
3427 {
3428 res = cp_walk_tree (&s, await_statement_walker,walk_tree_1 (&s, await_statement_walker, d, nullptr, cp_walk_subtrees
)
3429 d, NULL)walk_tree_1 (&s, await_statement_walker, d, nullptr, cp_walk_subtrees
)
;
3430 if (res)
3431 return res;
3432 }
3433 *do_subtree = 0; /* Done subtrees. */
3434 return NULL_TREE(tree) nullptr;
3435 }
3436
3437 /* We have something to be handled as a single statement. We have to handle
3438 a few statements specially where await statements have to be moved out of
3439 constructs. */
3440 tree expr = *stmt;
3441 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == CLEANUP_POINT_EXPR)
3442 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3442, __FUNCTION__)))))
;
3443 STRIP_NOPS (expr)(expr) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((expr)))))
;
3444
3445 if (STATEMENT_CLASS_P (expr)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code
) (expr)->base.code))] == tcc_statement)
)
3446 switch (TREE_CODE (expr)((enum tree_code) (expr)->base.code))
3447 {
3448 /* Unless it's a special case, just walk the subtrees as usual. */
3449 default: return NULL_TREE(tree) nullptr;
3450
3451 /* When we have a conditional expression, which contains one or more
3452 await expressions, we have to break the condition out into a
3453 regular statement so that the control flow introduced by the await
3454 transforms can be implemented. */
3455 case IF_STMT:
3456 {
3457 tree *await_ptr;
3458 hash_set<tree> visited;
3459 /* Transform 'if (cond with awaits) then stmt1 else stmt2' into
3460 bool cond = cond with awaits.
3461 if (cond) then stmt1 else stmt2. */
3462 tree if_stmt = *stmt;
3463 /* We treat the condition as if it was a stand-alone statement,
3464 to see if there are any await expressions which will be analyzed
3465 and registered. */
3466 if (!(cp_walk_tree (&IF_COND (if_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3466, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3466, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3467 find_any_await, &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3466, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3466, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
))
3468 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3469
3470 gcc_checking_assert (!awpts->bind_stack->is_empty())((void)(!(!awpts->bind_stack->is_empty()) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3470, __FUNCTION__), 0 : 0))
;
3471 tree& bind_expr = awpts->bind_stack->last ();
3472 tree newvar = add_var_to_bind (bind_expr, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE],
3473 "ifcd", awpts->cond_number++);
3474 tree insert_list = push_stmt_list ();
3475 tree cond_inner = IF_COND (if_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3475, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3475, __FUNCTION__)))))
;
3476 if (TREE_CODE (cond_inner)((enum tree_code) (cond_inner)->base.code) == CLEANUP_POINT_EXPR)
3477 cond_inner = TREE_OPERAND (cond_inner, 0)(*((const_cast<tree*> (tree_operand_check ((cond_inner)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3477, __FUNCTION__)))))
;
3478 add_decl_expr (newvar);
3479 location_t sloc = EXPR_LOCATION (IF_COND (if_stmt))(((((*((const_cast<tree*> (tree_operand_check (((tree_check
((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__))))))) && ((tree_code_type_tmpl <
0>::tree_code_type[(int) (((enum tree_code) (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__)))))))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) (((*((const_cast<tree*> (tree_operand_check
(((tree_check ((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__)))))))->base.code))]) <= tcc_expression
)) ? ((*((const_cast<tree*> (tree_operand_check (((tree_check
((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3479, __FUNCTION__))))))->exp.locus : ((location_t) 0))
;
3480 /* We want to initialize the new variable with the expression
3481 that contains the await(s) and potentially also needs to
3482 have truth_if expressions expanded. */
3483 tree new_s = cp_build_init_expr (sloc, newvar, cond_inner);
3484 finish_expr_stmt (new_s);
3485 IF_COND (if_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((if_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3485, __FUNCTION__, (IF_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3485, __FUNCTION__)))))
= newvar;
3486 add_stmt (if_stmt);
3487 *stmt = pop_stmt_list (insert_list);
3488 /* So now walk the new statement list. */
3489 res = cp_walk_tree (stmt, await_statement_walker, d, NULL)walk_tree_1 (stmt, await_statement_walker, d, nullptr, cp_walk_subtrees
)
;
3490 *do_subtree = 0; /* Done subtrees. */
3491 return res;
3492 }
3493 break;
3494 case FOR_STMT:
3495 {
3496 tree *await_ptr;
3497 hash_set<tree> visited;
3498 /* for loops only need special treatment if the condition or the
3499 iteration expression contain a co_await. */
3500 tree for_stmt = *stmt;
3501 /* At present, the FE always generates a separate initializer for
3502 the FOR_INIT_STMT, when the expression has an await. Check that
3503 this assumption holds in the future. */
3504 gcc_checking_assert((void)(!(!(walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__, (FOR_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3506, __FUNCTION__), 0 : 0))
3505 (!(cp_walk_tree (&FOR_INIT_STMT (for_stmt), find_any_await,((void)(!(!(walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__, (FOR_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3506, __FUNCTION__), 0 : 0))
3506 &await_ptr, &visited)))((void)(!(!(walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__, (FOR_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3505, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3506, __FUNCTION__), 0 : 0))
;
3507
3508 visited.empty ();
3509 bool for_cond_await
3510 = cp_walk_tree (&FOR_COND (for_stmt), find_any_await,walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3510, __FUNCTION__, (FOR_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3510, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3511 &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3510, __FUNCTION__, (FOR_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3510, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
;
3512
3513 visited.empty ();
3514 bool for_expr_await
3515 = cp_walk_tree (&FOR_EXPR (for_stmt), find_any_await,walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3515, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3515, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3516 &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3515, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3515, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
;
3517
3518 /* If the condition has an await, then we will need to rewrite the
3519 loop as
3520 for (init expression;true;iteration expression) {
3521 condition = await expression;
3522 if (condition)
3523 break;
3524 ...
3525 }
3526 */
3527 if (for_cond_await)
3528 {
3529 tree insert_list = push_stmt_list ();
3530 /* This will be expanded when the revised body is handled. */
3531 coro_build_add_if_not_cond_break (FOR_COND (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3531, __FUNCTION__, (FOR_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3531, __FUNCTION__)))))
);
3532 /* .. add the original for body. */
3533 add_stmt (FOR_BODY (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3533, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3533, __FUNCTION__)))))
);
3534 /* To make the new for body. */
3535 FOR_BODY (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3535, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3535, __FUNCTION__)))))
= pop_stmt_list (insert_list);
3536 FOR_COND (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3536, __FUNCTION__, (FOR_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3536, __FUNCTION__)))))
= boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE];
3537 }
3538 /* If the iteration expression has an await, it's a bit more
3539 tricky.
3540 for (init expression;condition;) {
3541 ...
3542 iteration_expr_label:
3543 iteration expression with await;
3544 }
3545 but, then we will need to re-write any continue statements into
3546 'goto iteration_expr_label:'.
3547 */
3548 if (for_expr_await)
3549 {
3550 location_t sloc = EXPR_LOCATION (FOR_EXPR (for_stmt))(((((*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__))))))) && ((tree_code_type_tmpl <
0>::tree_code_type[(int) (((enum tree_code) (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__)))))))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) (((*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__)))))))->base.code))]) <= tcc_expression
)) ? ((*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3550, __FUNCTION__))))))->exp.locus : ((location_t) 0))
;
3551 tree insert_list = push_stmt_list ();
3552 /* The original for body. */
3553 add_stmt (FOR_BODY (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3553, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3553, __FUNCTION__)))))
);
3554 char *buf = xasprintf ("for.iter.expr.%u", awpts->cond_number++);
3555 tree it_expr_label
3556 = create_named_label_with_ctx (sloc, buf, NULL_TREE(tree) nullptr);
3557 free (buf);
3558 add_stmt (build_stmt (sloc, LABEL_EXPR, it_expr_label));
3559 tree for_expr = FOR_EXPR (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3559, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3559, __FUNCTION__)))))
;
3560 /* Present the iteration expression as a statement. */
3561 if (TREE_CODE (for_expr)((enum tree_code) (for_expr)->base.code) == CLEANUP_POINT_EXPR)
3562 for_expr = TREE_OPERAND (for_expr, 0)(*((const_cast<tree*> (tree_operand_check ((for_expr), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3562, __FUNCTION__)))))
;
3563 STRIP_NOPS (for_expr)(for_expr) = tree_strip_nop_conversions ((const_cast<union
tree_node *> (((for_expr)))))
;
3564 finish_expr_stmt (for_expr);
3565 FOR_EXPR (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3565, __FUNCTION__, (FOR_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3565, __FUNCTION__)))))
= NULL_TREE(tree) nullptr;
3566 FOR_BODY (for_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3566, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3566, __FUNCTION__)))))
= pop_stmt_list (insert_list);
3567 /* rewrite continue statements to goto label. */
3568 hash_set<tree> visited_continue;
3569 if ((res = cp_walk_tree (&FOR_BODY (for_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3569, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3569, __FUNCTION__))))), replace_continue, &it_expr_label
, &visited_continue, cp_walk_subtrees)
3570 replace_continue, &it_expr_label, &visited_continue)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3569, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3569, __FUNCTION__))))), replace_continue, &it_expr_label
, &visited_continue, cp_walk_subtrees)
))
3571 return res;
3572 }
3573
3574 /* So now walk the body statement (list), if there were no await
3575 expressions, then this handles the original body - and either
3576 way we will have finished with this statement. */
3577 res = cp_walk_tree (&FOR_BODY (for_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3577, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3577, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
3578 await_statement_walker, d, NULL)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((for_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3577, __FUNCTION__, (FOR_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3577, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
;
3579 *do_subtree = 0; /* Done subtrees. */
3580 return res;
3581 }
3582 break;
3583 case WHILE_STMT:
3584 {
3585 /* We turn 'while (cond with awaits) stmt' into
3586 while (true) {
3587 if (!(cond with awaits))
3588 break;
3589 stmt..
3590 } */
3591 tree *await_ptr;
3592 hash_set<tree> visited;
3593 tree while_stmt = *stmt;
3594 if (!(cp_walk_tree (&WHILE_COND (while_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3594, __FUNCTION__, (WHILE_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3594, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3595 find_any_await, &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3594, __FUNCTION__, (WHILE_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3594, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
))
3596 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3597
3598 tree insert_list = push_stmt_list ();
3599 coro_build_add_if_not_cond_break (WHILE_COND (while_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3599, __FUNCTION__, (WHILE_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3599, __FUNCTION__)))))
);
3600 /* The original while body. */
3601 add_stmt (WHILE_BODY (while_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3601, __FUNCTION__, (WHILE_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3601, __FUNCTION__)))))
);
3602 /* The new while body. */
3603 WHILE_BODY (while_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3603, __FUNCTION__, (WHILE_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3603, __FUNCTION__)))))
= pop_stmt_list (insert_list);
3604 WHILE_COND (while_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3604, __FUNCTION__, (WHILE_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3604, __FUNCTION__)))))
= boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE];
3605 /* So now walk the new statement list. */
3606 res = cp_walk_tree (&WHILE_BODY (while_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3606, __FUNCTION__, (WHILE_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3606, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
3607 await_statement_walker, d, NULL)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((while_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3606, __FUNCTION__, (WHILE_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3606, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
;
3608 *do_subtree = 0; /* Done subtrees. */
3609 return res;
3610 }
3611 break;
3612 case DO_STMT:
3613 {
3614 /* We turn do stmt while (cond with awaits) into:
3615 do {
3616 stmt..
3617 if (!(cond with awaits))
3618 break;
3619 } while (true); */
3620 tree do_stmt = *stmt;
3621 tree *await_ptr;
3622 hash_set<tree> visited;
3623 if (!(cp_walk_tree (&DO_COND (do_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3623, __FUNCTION__, (DO_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3623, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3624 find_any_await, &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3623, __FUNCTION__, (DO_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3623, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
))
3625 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3626
3627 tree insert_list = push_stmt_list ();
3628 /* The original do stmt body. */
3629 add_stmt (DO_BODY (do_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3629, __FUNCTION__, (DO_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3629, __FUNCTION__)))))
);
3630 coro_build_add_if_not_cond_break (DO_COND (do_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3630, __FUNCTION__, (DO_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3630, __FUNCTION__)))))
);
3631 /* The new while body. */
3632 DO_BODY (do_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3632, __FUNCTION__, (DO_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3632, __FUNCTION__)))))
= pop_stmt_list (insert_list);
3633 DO_COND (do_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3633, __FUNCTION__, (DO_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3633, __FUNCTION__)))))
= boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE];
3634 /* So now walk the new statement list. */
3635 res = cp_walk_tree (&DO_BODY (do_stmt), await_statement_walker,walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3635, __FUNCTION__, (DO_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3635, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
3636 d, NULL)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((do_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3635, __FUNCTION__, (DO_STMT)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3635, __FUNCTION__))))), await_statement_walker, d, nullptr
, cp_walk_subtrees)
;
3637 *do_subtree = 0; /* Done subtrees. */
3638 return res;
3639 }
3640 break;
3641 case SWITCH_STMT:
3642 {
3643 /* We turn 'switch (cond with awaits) stmt' into
3644 switch_type cond = cond with awaits
3645 switch (cond) stmt. */
3646 tree sw_stmt = *stmt;
3647 tree *await_ptr;
3648 hash_set<tree> visited;
3649 if (!(cp_walk_tree (&SWITCH_STMT_COND (sw_stmt),walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3649, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3649, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3650 find_any_await, &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3649, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3649, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
))
3651 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3652
3653 gcc_checking_assert (!awpts->bind_stack->is_empty())((void)(!(!awpts->bind_stack->is_empty()) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3653, __FUNCTION__), 0 : 0))
;
3654 /* Build a variable to hold the condition, this will be
3655 included in the frame as a local var. */
3656 tree& bind_expr = awpts->bind_stack->last ();
3657 tree sw_type = SWITCH_STMT_TYPE (sw_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3657, __FUNCTION__, (SWITCH_STMT)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3657, __FUNCTION__)))))
;
3658 tree newvar = add_var_to_bind (bind_expr, sw_type, "swch",
3659 awpts->cond_number++);
3660 tree insert_list = push_stmt_list ();
3661 add_decl_expr (newvar);
3662
3663 tree cond_inner = SWITCH_STMT_COND (sw_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3663, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3663, __FUNCTION__)))))
;
3664 if (TREE_CODE (cond_inner)((enum tree_code) (cond_inner)->base.code) == CLEANUP_POINT_EXPR)
3665 cond_inner = TREE_OPERAND (cond_inner, 0)(*((const_cast<tree*> (tree_operand_check ((cond_inner)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3665, __FUNCTION__)))))
;
3666 location_t sloc = EXPR_LOCATION (SWITCH_STMT_COND (sw_stmt))(((((*((const_cast<tree*> (tree_operand_check (((tree_check
((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__))))))) && ((tree_code_type_tmpl <
0>::tree_code_type[(int) (((enum tree_code) (((*((const_cast
<tree*> (tree_operand_check (((tree_check ((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__)))))))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) (((*((const_cast<tree*> (tree_operand_check
(((tree_check ((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__)))))))->base.code))]) <= tcc_expression
)) ? ((*((const_cast<tree*> (tree_operand_check (((tree_check
((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3666, __FUNCTION__))))))->exp.locus : ((location_t) 0))
;
3667 tree new_s = cp_build_init_expr (sloc, newvar,
3668 cond_inner);
3669 finish_expr_stmt (new_s);
3670 SWITCH_STMT_COND (sw_stmt)(*((const_cast<tree*> (tree_operand_check (((tree_check
((sw_stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3670, __FUNCTION__, (SWITCH_STMT)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3670, __FUNCTION__)))))
= newvar;
3671 /* Now add the switch statement with the condition re-
3672 written to use the local var. */
3673 add_stmt (sw_stmt);
3674 *stmt = pop_stmt_list (insert_list);
3675 /* Process the expanded list. */
3676 res = cp_walk_tree (stmt, await_statement_walker,walk_tree_1 (stmt, await_statement_walker, d, nullptr, cp_walk_subtrees
)
3677 d, NULL)walk_tree_1 (stmt, await_statement_walker, d, nullptr, cp_walk_subtrees
)
;
3678 *do_subtree = 0; /* Done subtrees. */
3679 return res;
3680 }
3681 break;
3682 case CO_RETURN_EXPR:
3683 {
3684 /* Expand the co_return as per [stmt.return.coroutine]
3685 - for co_return;
3686 { p.return_void (); goto final_suspend; }
3687 - for co_return [void expr];
3688 { expr; p.return_void(); goto final_suspend;}
3689 - for co_return [non void expr];
3690 { p.return_value(expr); goto final_suspend; } */
3691 location_t loc = EXPR_LOCATION (expr)((((expr)) && ((tree_code_type_tmpl <0>::tree_code_type
[(int) (((enum tree_code) ((expr))->base.code))]) >= tcc_reference
&& (tree_code_type_tmpl <0>::tree_code_type[(int
) (((enum tree_code) ((expr))->base.code))]) <= tcc_expression
)) ? (expr)->exp.locus : ((location_t) 0))
;
3692 tree call = TREE_OPERAND (expr, 1)(*((const_cast<tree*> (tree_operand_check ((expr), (1),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3692, __FUNCTION__)))))
;
3693 expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3693, __FUNCTION__)))))
;
3694 tree ret_list = push_stmt_list ();
3695 /* [stmt.return.coroutine], 2.2
3696 If expr is present and void, it is placed immediately before
3697 the call for return_void; */
3698 if (expr && VOID_TYPE_P (TREE_TYPE (expr))(((enum tree_code) (((contains_struct_check ((expr), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3698, __FUNCTION__))->typed.type))->base.code) == VOID_TYPE
)
)
3699 finish_expr_stmt (expr);
3700 /* Insert p.return_{void,value(expr)}. */
3701 finish_expr_stmt (call);
3702 TREE_USED (awpts->fs_label)((awpts->fs_label)->base.used_flag) = 1;
3703 add_stmt (build_stmt (loc, GOTO_EXPR, awpts->fs_label));
3704 *stmt = pop_stmt_list (ret_list);
3705 res = cp_walk_tree (stmt, await_statement_walker, d, NULL)walk_tree_1 (stmt, await_statement_walker, d, nullptr, cp_walk_subtrees
)
;
3706 /* Once this is complete, we will have processed subtrees. */
3707 *do_subtree = 0;
3708 return res;
3709 }
3710 break;
3711 case HANDLER:
3712 {
3713 /* [expr.await] An await-expression shall appear only in a
3714 potentially-evaluated expression within the compound-statement
3715 of a function-body outside of a handler. */
3716 tree *await_ptr;
3717 hash_set<tree> visited;
3718 if (!(cp_walk_tree (&HANDLER_BODY (expr), find_any_await,walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3718, __FUNCTION__, (HANDLER)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3718, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
3719 &await_ptr, &visited)walk_tree_1 (&(*((const_cast<tree*> (tree_operand_check
(((tree_check ((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3718, __FUNCTION__, (HANDLER)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3718, __FUNCTION__))))), find_any_await, &await_ptr, &
visited, cp_walk_subtrees)
))
3720 return NULL_TREE(tree) nullptr; /* All OK. */
3721 location_t loc = EXPR_LOCATION (*await_ptr)((((*await_ptr)) && ((tree_code_type_tmpl <0>::
tree_code_type[(int) (((enum tree_code) ((*await_ptr))->base
.code))]) >= tcc_reference && (tree_code_type_tmpl
<0>::tree_code_type[(int) (((enum tree_code) ((*await_ptr
))->base.code))]) <= tcc_expression)) ? (*await_ptr)->
exp.locus : ((location_t) 0))
;
3722 error_at (loc, "await expressions are not permitted in handlers");
3723 return NULL_TREE(tree) nullptr; /* This is going to fail later anyway. */
3724 }
3725 break;
3726 }
3727 else if (EXPR_P (expr)((tree_code_type_tmpl <0>::tree_code_type[(int) (((enum
tree_code) (expr)->base.code))]) >= tcc_reference &&
(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum
tree_code) (expr)->base.code))]) <= tcc_expression)
)
3728 {
3729 hash_set<tree> visited;
3730 tree *await_ptr;
3731 if (!(cp_walk_tree (stmt, find_any_await, &await_ptr, &visited)walk_tree_1 (stmt, find_any_await, &await_ptr, &visited
, cp_walk_subtrees)
))
3732 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3733
3734 visited.empty ();
3735 awpts->saw_awaits = 0;
3736 hash_set<tree> truth_aoif_to_expand;
3737 awpts->truth_aoif_to_expand = &truth_aoif_to_expand;
3738 awpts->needs_truth_if_exp = false;
3739 awpts->has_awaiter_init = false;
3740 if ((res = cp_walk_tree (stmt, analyze_expression_awaits, d, &visited)walk_tree_1 (stmt, analyze_expression_awaits, d, &visited
, cp_walk_subtrees)
))
3741 return res;
3742 *do_subtree = 0; /* Done subtrees. */
3743 if (!awpts->saw_awaits)
3744 return NULL_TREE(tree) nullptr; /* Nothing special to do here. */
3745
3746 if (awpts->needs_truth_if_exp)
3747 {
3748 /* If a truth-and/or-if expression has an await expression in the
3749 conditionally-taken branch, then it must be rewritten into a
3750 regular conditional. */
3751 truth_if_transform xf = {stmt, NULL_TREE(tree) nullptr, &truth_aoif_to_expand};
3752 if ((res = cp_walk_tree (stmt, expand_one_truth_if, &xf, NULL)walk_tree_1 (stmt, expand_one_truth_if, &xf, nullptr, cp_walk_subtrees
)
))
3753 return res;
3754 }
3755 /* Process this statement, which contains at least one await expression
3756 to 'promote' temporary values to a coroutine frame slot. */
3757 return maybe_promote_temps (stmt, d);
3758 }
3759 /* Continue recursion, if needed. */
3760 return res;
3761}
3762
3763/* For figuring out what param usage we have. */
3764
3765struct param_frame_data
3766{
3767 tree *field_list;
3768 hash_map<tree, param_info> *param_uses;
3769 hash_set<tree *> *visited;
3770 location_t loc;
3771 bool param_seen;
3772};
3773
3774/* A tree walk callback that rewrites each parm use to the local variable
3775 that represents its copy in the frame. */
3776
3777static tree
3778rewrite_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED__attribute__ ((__unused__)), void *d)
3779{
3780 param_frame_data *data = (param_frame_data *) d;
3781
3782 /* For lambda closure content, we have to look specifically. */
3783 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*stmt)((tree_check3 ((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3783, __FUNCTION__, (VAR_DECL), (PARM_DECL), (RESULT_DECL))
) ->decl_common.decl_flag_2)
)
3784 {
3785 tree t = DECL_VALUE_EXPR (*stmt)(decl_value_expr_lookup ((contains_struct_check ((*stmt), (TS_DECL_WRTL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3785, __FUNCTION__))))
;
3786 return cp_walk_tree (&t, rewrite_param_uses, d, NULL)walk_tree_1 (&t, rewrite_param_uses, d, nullptr, cp_walk_subtrees
)
;
3787 }
3788
3789 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) != PARM_DECL)
3790 return NULL_TREE(tree) nullptr;
3791
3792 /* If we already saw the containing expression, then we're done. */
3793 if (data->visited->add (stmt))
3794 return NULL_TREE(tree) nullptr;
3795
3796 bool existed;
3797 param_info &parm = data->param_uses->get_or_insert (*stmt, &existed);
3798 gcc_checking_assert (existed)((void)(!(existed) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3798, __FUNCTION__), 0 : 0))
;
3799
3800 *stmt = parm.copy_var;
3801 return NULL_TREE(tree) nullptr;
3802}
3803
3804/* Build up a set of info that determines how each param copy will be
3805 handled. */
3806
3807static hash_map<tree, param_info> *
3808analyze_fn_parms (tree orig)
3809{
3810 if (!DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3810, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
)
3811 return NULLnullptr;
3812
3813 hash_map<tree, param_info> *param_uses = new hash_map<tree, param_info>;
3814
3815 /* Build a hash map with an entry for each param.
3816 The key is the param tree.
3817 Then we have an entry for the frame field name.
3818 Then a cache for the field ref when we come to use it.
3819 Then a tree list of the uses.
3820 The second two entries start out empty - and only get populated
3821 when we see uses. */
3822 bool lambda_p = LAMBDA_FUNCTION_P (orig)((((enum tree_code) (orig)->base.code) == FUNCTION_DECL ||
(((enum tree_code) (orig)->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((orig
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) && (((tree_not_check2 (
((tree_check ((((contains_struct_check ((orig), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.name)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (IDENTIFIER_NODE)))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TREE_VEC), (SSA_NAME)))->base.u.bits
.lang_flag_2)) && ((__extension__ ({ struct lang_decl
*lt = ((contains_struct_check (((((enum tree_code) (orig)->
base.code) == TEMPLATE_DECL ? ((struct tree_template_decl *)(
const_cast<union tree_node *> ((((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TEMPLATE_DECL))))))))->result : orig
)), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) (orig)->base.code) == FUNCTION_DECL || (
((enum tree_code) (orig)->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check ((orig
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__); &lt->u.fn; })->ovl_op_code) ==
OVL_OP_CALL_EXPR) && (((enum tree_code) ((!(! (((contains_struct_check
((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL]))->base.code) == RECORD_TYPE && ((((
tree_class_check ((((tree_class_check (((!(! (((contains_struct_check
((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name) && (tree_code_type_tmpl
<0>::tree_code_type[(int) (((enum tree_code) (((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name))->base.code))
] == tcc_declaration) ? ((contains_struct_check ((((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name)), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.name) : ((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name))) && ((tree_check
((((((tree_class_check ((((tree_class_check (((!(! (((contains_struct_check
((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name) && (tree_code_type_tmpl
<0>::tree_code_type[(int) (((enum tree_code) (((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name))->base.code))
] == tcc_declaration) ? ((contains_struct_check ((((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name)), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.name) : ((tree_class_check
((((tree_class_check (((!(! (((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context)) || ((enum tree_code
) (((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context))->base.code
) == TRANSLATION_UNIT_DECL) ? ((contains_struct_check ((orig)
, (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->decl_minimal.context) : cp_global_trees
[CPTI_GLOBAL])), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.main_variant)), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__))->type_common.name)))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3822, __FUNCTION__, (IDENTIFIER_NODE)))->base.protected_flag
)))
;
3823
3824 unsigned no_name_parm = 0;
3825 for (tree arg = DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3825, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr; arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3825, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3825, __FUNCTION__))->common.chain))
)
3826 {
3827 bool existed;
3828 param_info &parm = param_uses->get_or_insert (arg, &existed);
3829 gcc_checking_assert (!existed)((void)(!(!existed) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3829, __FUNCTION__), 0 : 0))
;
3830 parm.body_uses = NULLnullptr;
3831 tree actual_type = TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3831, __FUNCTION__))->typed.type)
;
3832 actual_type = complete_type_or_else (actual_type, orig);
3833 if (actual_type == NULL_TREE(tree) nullptr)
3834 actual_type = error_mark_nodeglobal_trees[TI_ERROR_MARK];
3835 parm.orig_type = actual_type;
3836 parm.by_ref = parm.pt_ref = parm.rv_ref = false;
3837 if (TREE_CODE (actual_type)((enum tree_code) (actual_type)->base.code) == REFERENCE_TYPE)
3838 {
3839 /* If the user passes by reference, then we will save the
3840 pointer to the original. As noted in
3841 [dcl.fct.def.coroutine] / 13, if the lifetime of the
3842 referenced item ends and then the coroutine is resumed,
3843 we have UB; well, the user asked for it. */
3844 if (TYPE_REF_IS_RVALUE (actual_type)((tree_check ((actual_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3844, __FUNCTION__, (REFERENCE_TYPE)))->base.private_flag
)
)
3845 parm.rv_ref = true;
3846 else
3847 parm.pt_ref = true;
3848 }
3849 else if (TYPE_REF_P (DECL_ARG_TYPE (arg))(((enum tree_code) (((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3849, __FUNCTION__, (PARM_DECL)))->decl_common.initial))
->base.code) == REFERENCE_TYPE)
)
3850 parm.by_ref = true;
3851
3852 parm.frame_type = actual_type;
3853
3854 parm.this_ptr = is_this_parameter (arg);
3855 parm.lambda_cobj = lambda_p && DECL_NAME (arg)((contains_struct_check ((arg), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3855, __FUNCTION__))->decl_minimal.name)
== closure_identifiercp_global_trees[CPTI_CLOSURE_IDENTIFIER];
3856
3857 tree name = DECL_NAME (arg)((contains_struct_check ((arg), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3857, __FUNCTION__))->decl_minimal.name)
;
3858 if (!name)
3859 {
3860 char *buf = xasprintf ("_Coro_unnamed_parm_%d", no_name_parm++);
3861 name = get_identifier (buf)(__builtin_constant_p (buf) ? get_identifier_with_length ((buf
), strlen (buf)) : get_identifier (buf))
;
3862 free (buf);
3863 }
3864 parm.field_id = name;
3865
3866 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type)(((tree_class_check ((parm.frame_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3866, __FUNCTION__))->type_common.lang_flag_4))
)
3867 {
3868 char *buf = xasprintf ("%s%s_live", DECL_NAME (arg)((contains_struct_check ((arg), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3868, __FUNCTION__))->decl_minimal.name)
? "_Coro_" : "",
3869 IDENTIFIER_POINTER (name)((const char *) (tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3869, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
)
);
3870 parm.guard_var
3871 = coro_build_artificial_var (UNKNOWN_LOCATION((location_t) 0), get_identifier (buf)(__builtin_constant_p (buf) ? get_identifier_with_length ((buf
), strlen (buf)) : get_identifier (buf))
,
3872 boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], orig,
3873 boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE]);
3874 free (buf);
3875 parm.trivial_dtor = false;
3876 }
3877 else
3878 parm.trivial_dtor = true;
3879 }
3880
3881 return param_uses;
3882}
3883
3884/* Small helper for the repetitive task of adding a new field to the coro
3885 frame type. */
3886
3887static tree
3888coro_make_frame_entry (tree *field_list, const char *name, tree fld_type,
3889 location_t loc)
3890{
3891 tree id = get_identifier (name)(__builtin_constant_p (name) ? get_identifier_with_length ((name
), strlen (name)) : get_identifier (name))
;
3892 tree decl = build_decl (loc, FIELD_DECL, id, fld_type);
3893 DECL_CHAIN (decl)(((contains_struct_check (((contains_struct_check ((decl), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3893, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3893, __FUNCTION__))->common.chain))
= *field_list;
3894 *field_list = decl;
3895 return id;
3896}
3897
3898/* For recording local variable usage. */
3899
3900struct local_vars_frame_data
3901{
3902 tree *field_list;
3903 hash_map<tree, local_var_info> *local_var_uses;
3904 unsigned int nest_depth, bind_indx;
3905 location_t loc;
3906 bool saw_capture;
3907 bool local_var_seen;
3908};
3909
3910/* A tree-walk callback that processes one bind expression noting local
3911 variables, and making a coroutine frame slot available for those that
3912 need it, so that they can be 'promoted' across suspension points. */
3913
3914static tree
3915register_local_var_uses (tree *stmt, int *do_subtree, void *d)
3916{
3917 local_vars_frame_data *lvd = (local_vars_frame_data *) d;
3918
3919 /* As we enter a bind expression - record the vars there and then recurse.
3920 As we exit drop the nest depth.
3921 The bind index is a growing count of how many bind indices we've seen.
3922 We build a space in the frame for each local var. */
3923
3924 if (TREE_CODE (*stmt)((enum tree_code) (*stmt)->base.code) == BIND_EXPR)
3925 {
3926 tree lvar;
3927 unsigned serial = 0;
3928 for (lvar = BIND_EXPR_VARS (*stmt)((*((const_cast<tree*> (tree_operand_check (((tree_check
((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3928, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3928, __FUNCTION__))))))
; lvar != NULLnullptr;
3929 lvar = DECL_CHAIN (lvar)(((contains_struct_check (((contains_struct_check ((lvar), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3929, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3929, __FUNCTION__))->common.chain))
)
3930 {
3931 bool existed;
3932 local_var_info &local_var
3933 = lvd->local_var_uses->get_or_insert (lvar, &existed);
3934 gcc_checking_assert (!existed)((void)(!(!existed) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3934, __FUNCTION__), 0 : 0))
;
3935 local_var.def_loc = DECL_SOURCE_LOCATION (lvar)((contains_struct_check ((lvar), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3935, __FUNCTION__))->decl_minimal.locus)
;
3936 tree lvtype = TREE_TYPE (lvar)((contains_struct_check ((lvar), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3936, __FUNCTION__))->typed.type)
;
3937 local_var.frame_type = lvtype;
3938 local_var.field_idx = local_var.field_id = NULL_TREE(tree) nullptr;
3939
3940 /* Make sure that we only present vars to the tests below. */
3941 if (TREE_CODE (lvar)((enum tree_code) (lvar)->base.code) == TYPE_DECL
3942 || TREE_CODE (lvar)((enum tree_code) (lvar)->base.code) == NAMESPACE_DECL)
3943 continue;
3944
3945 /* We don't move static vars into the frame. */
3946 local_var.is_static = TREE_STATIC (lvar)((lvar)->base.static_flag);
3947 if (local_var.is_static)
3948 continue;
3949
3950 poly_uint64 size;
3951 if (TREE_CODE (lvtype)((enum tree_code) (lvtype)->base.code) == ARRAY_TYPE
3952 && !poly_int_tree_p (DECL_SIZE_UNIT (lvar)((contains_struct_check ((lvar), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3952, __FUNCTION__))->decl_common.size_unit)
, &size))
3953 {
3954 sorry_at (local_var.def_loc, "variable length arrays are not"
3955 " yet supported in coroutines");
3956 /* Ignore it, this is broken anyway. */
3957 continue;
3958 }
3959
3960 lvd->local_var_seen = true;
3961 /* If this var is a lambda capture proxy, we want to leave it alone,
3962 and later rewrite the DECL_VALUE_EXPR to indirect through the
3963 frame copy of the pointer to the lambda closure object. */
3964 local_var.is_lambda_capture = is_capture_proxy (lvar);
3965 if (local_var.is_lambda_capture)
3966 continue;
3967
3968 /* If a variable has a value expression, then that's what needs
3969 to be processed. */
3970 local_var.has_value_expr_p = DECL_HAS_VALUE_EXPR_P (lvar)((tree_check3 ((lvar), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3970, __FUNCTION__, (VAR_DECL), (PARM_DECL), (RESULT_DECL))
) ->decl_common.decl_flag_2)
;
3971 if (local_var.has_value_expr_p)
3972 continue;
3973
3974 /* Make names depth+index unique, so that we can support nested
3975 scopes with identically named locals and still be able to
3976 identify them in the coroutine frame. */
3977 tree lvname = DECL_NAME (lvar)((contains_struct_check ((lvar), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3977, __FUNCTION__))->decl_minimal.name)
;
3978 char *buf = NULLnullptr;
3979
3980 /* The outermost bind scope contains the artificial variables that
3981 we inject to implement the coro state machine. We want to be able
3982 to inspect these in debugging. */
3983 if (lvname != NULL_TREE(tree) nullptr && lvd->nest_depth == 0)
3984 buf = xasprintf ("%s", IDENTIFIER_POINTER (lvname)((const char *) (tree_check ((lvname), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3984, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
)
);
3985 else if (lvname != NULL_TREE(tree) nullptr)
3986 buf = xasprintf ("%s_%u_%u", IDENTIFIER_POINTER (lvname)((const char *) (tree_check ((lvname), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 3986, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str
)
,
3987 lvd->nest_depth, lvd->bind_indx);
3988 else
3989 buf = xasprintf ("_D%u_%u_%u", lvd->nest_depth, lvd->bind_indx,
3990 serial++);
3991
3992 /* TODO: Figure out if we should build a local type that has any
3993 excess alignment or size from the original decl. */
3994 local_var.field_id = coro_make_frame_entry (lvd->field_list, buf,
3995 lvtype, lvd->loc);
3996 free (buf);
3997 /* We don't walk any of the local var sub-trees, they won't contain
3998 any bind exprs. */
3999 }
4000 lvd->bind_indx++;
4001 lvd->nest_depth++;
4002 cp_walk_tree (&BIND_EXPR_BODY (*stmt), register_local_var_uses, d, NULL)walk_tree_1 (&((*((const_cast<tree*> (tree_operand_check
(((tree_check ((*stmt), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4002, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4002, __FUNCTION__)))))), register_local_var_uses, d, nullptr
, cp_walk_subtrees)
;
4003 *do_subtree = 0; /* We've done this. */
4004 lvd->nest_depth--;
4005 }
4006 return NULL_TREE(tree) nullptr;
4007}
4008
4009/* Build, return FUNCTION_DECL node based on ORIG with a type FN_TYPE which has
4010 a single argument of type CORO_FRAME_PTR. Build the actor function if
4011 ACTOR_P is true, otherwise the destroy. */
4012
4013static tree
4014coro_build_actor_or_destroy_function (tree orig, tree fn_type,
4015 tree coro_frame_ptr, bool actor_p)
4016{
4017 location_t loc = DECL_SOURCE_LOCATION (orig)((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4017, __FUNCTION__))->decl_minimal.locus)
;
4018 tree fn
4019 = build_lang_decl (FUNCTION_DECL, copy_node (DECL_NAME (orig)((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4019, __FUNCTION__))->decl_minimal.name)
), fn_type);
4020
4021 /* Allow for locating the ramp (original) function from this one. */
4022 if (!to_ramp)
4023 to_ramp = hash_map<tree, tree>::create_ggc (10);
4024 to_ramp->put (fn, orig);
4025
4026 DECL_CONTEXT (fn)((contains_struct_check ((fn), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4026, __FUNCTION__))->decl_minimal.context)
= DECL_CONTEXT (orig)((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4026, __FUNCTION__))->decl_minimal.context)
;
4027 DECL_SOURCE_LOCATION (fn)((contains_struct_check ((fn), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4027, __FUNCTION__))->decl_minimal.locus)
= loc;
4028 DECL_ARTIFICIAL (fn)((contains_struct_check ((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4028, __FUNCTION__))->decl_common.artificial_flag)
= true;
4029 DECL_INITIAL (fn)((contains_struct_check ((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4029, __FUNCTION__))->decl_common.initial)
= error_mark_nodeglobal_trees[TI_ERROR_MARK];
4030
4031 tree id = get_identifier ("frame_ptr")(__builtin_constant_p ("frame_ptr") ? get_identifier_with_length
(("frame_ptr"), strlen ("frame_ptr")) : get_identifier ("frame_ptr"
))
;
4032 tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr);
4033 DECL_CONTEXT (fp)((contains_struct_check ((fp), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4033, __FUNCTION__))->decl_minimal.context)
= fn;
4034 DECL_ARG_TYPE (fp)((tree_check ((fp), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4034, __FUNCTION__, (PARM_DECL)))->decl_common.initial)
= type_passed_as (coro_frame_ptr);
4035 DECL_ARGUMENTS (fn)((tree_check ((fn), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4035, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
= fp;
4036
4037 /* Copy selected attributes from the original function. */
4038 TREE_USED (fn)((fn)->base.used_flag) = TREE_USED (orig)((orig)->base.used_flag);
4039 if (DECL_SECTION_NAME (orig)decl_section_name (orig))
4040 set_decl_section_name (fn, orig);
4041 /* Copy any alignment that the FE added. */
4042 if (DECL_ALIGN (orig)(((contains_struct_check ((orig), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4042, __FUNCTION__))->decl_common.align) ? ((unsigned)1)
<< (((contains_struct_check ((orig), (TS_DECL_COMMON),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4042, __FUNCTION__))->decl_common.align) - 1) : 0)
)
4043 SET_DECL_ALIGN (fn, DECL_ALIGN (orig))(((contains_struct_check ((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4043, __FUNCTION__))->decl_common.align) = ffs_hwi ((((contains_struct_check
((orig), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4043, __FUNCTION__))->decl_common.align) ? ((unsigned)1)
<< (((contains_struct_check ((orig), (TS_DECL_COMMON),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4043, __FUNCTION__))->decl_common.align) - 1) : 0)))
;
4044 /* Copy any alignment the user added. */
4045 DECL_USER_ALIGN (fn)((contains_struct_check ((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4045, __FUNCTION__))->base.u.bits.user_align)
= DECL_USER_ALIGN (orig)((contains_struct_check ((orig), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4045, __FUNCTION__))->base.u.bits.user_align)
;
4046 /* Apply attributes from the original fn. */
4047 DECL_ATTRIBUTES (fn)((contains_struct_check ((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4047, __FUNCTION__))->decl_common.attributes)
= copy_list (DECL_ATTRIBUTES (orig)((contains_struct_check ((orig), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4047, __FUNCTION__))->decl_common.attributes)
);
4048
4049 /* A void return. */
4050 tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_nodeglobal_trees[TI_VOID_TYPE]);
4051 DECL_CONTEXT (resdecl)((contains_struct_check ((resdecl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4051, __FUNCTION__))->decl_minimal.context)
= fn;
4052 DECL_ARTIFICIAL (resdecl)((contains_struct_check ((resdecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4052, __FUNCTION__))->decl_common.artificial_flag)
= 1;
4053 DECL_IGNORED_P (resdecl)((contains_struct_check ((resdecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4053, __FUNCTION__))->decl_common.ignored_flag)
= 1;
4054 DECL_RESULT (fn)((tree_check ((fn), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4054, __FUNCTION__, (FUNCTION_DECL)))->decl_non_common.result
)
= resdecl;
4055
4056 /* This is a coroutine component. */
4057 DECL_COROUTINE_P (fn)(__extension__ ({ struct lang_decl *lt = ((contains_struct_check
(((((enum tree_code) ((contains_struct_check ((fn), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__)))->base.code) == TEMPLATE_DECL ? ((struct
tree_template_decl *)(const_cast<union tree_node *> ((
((tree_check (((contains_struct_check ((fn), (TS_DECL_COMMON)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__, (TEMPLATE_DECL))))))))->result : (contains_struct_check
((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__)))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__))->decl_common.lang_specific); if (!(
((enum tree_code) ((contains_struct_check ((fn), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__)))->base.code) == FUNCTION_DECL || ((
(enum tree_code) ((contains_struct_check ((fn), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__)))->base.code) == TEMPLATE_DECL &&
((struct tree_template_decl *)(const_cast<union tree_node
*> ((((tree_check (((contains_struct_check ((fn), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__, (TEMPLATE_DECL))))))))->result != (tree
) nullptr && ((enum tree_code) (((struct tree_template_decl
*)(const_cast<union tree_node *> ((((tree_check (((contains_struct_check
((fn), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__, (TEMPLATE_DECL))))))))->result)->
base.code) == FUNCTION_DECL)) || lt->u.base.selector != lds_fn
) lang_check_failed ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4057, __FUNCTION__); &lt->u.fn; })->coroutine_p)
= 1;
4058
4059 /* Set up a means to find out if a decl is one of the helpers and, if so,
4060 which one. */
4061 if (coroutine_info *info = get_coroutine_info (orig))
4062 {
4063 gcc_checking_assert ((actor_p && info->actor_decl == NULL_TREE)((void)(!((actor_p && info->actor_decl == (tree) nullptr
) || info->destroy_decl == (tree) nullptr) ? fancy_abort (
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4064, __FUNCTION__), 0 : 0))
4064 || info->destroy_decl == NULL_TREE)((void)(!((actor_p && info->actor_decl == (tree) nullptr
) || info->destroy_decl == (tree) nullptr) ? fancy_abort (
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4064, __FUNCTION__), 0 : 0))
;
4065 if (actor_p)
4066 info->actor_decl = fn;
4067 else
4068 info->destroy_decl = fn;
4069 }
4070 return fn;
4071}
4072
4073/* Re-write the body as per [dcl.fct.def.coroutine] / 5. */
4074
4075static tree
4076coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig,
4077 hash_map<tree, param_info> *param_uses,
4078 tree resume_fn_ptr_type,
4079 tree& resume_idx_var, tree& fs_label)
4080{
4081 /* This will be our new outer scope. */
4082 tree update_body = build3 (BIND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], NULLnullptr, NULLnullptr, NULLnullptr);
4083 tree top_block = make_node (BLOCK);
4084 BIND_EXPR_BLOCK (update_body)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4084, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4084, __FUNCTION__))))))
= top_block;
4085 BIND_EXPR_BODY (update_body)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4085, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4085, __FUNCTION__))))))
= push_stmt_list ();
4086
4087 /* If the function has a top level bind expression, then connect that
4088 after first making sure we give it a new block. */
4089 tree first = expr_first (fnbody);
4090 if (first && TREE_CODE (first)((enum tree_code) (first)->base.code) == BIND_EXPR)
4091 {
4092 tree block = BIND_EXPR_BLOCK (first)((*((const_cast<tree*> (tree_operand_check (((tree_check
((first), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4092, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4092, __FUNCTION__))))))
;
4093 gcc_checking_assert (block)((void)(!(block) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4093, __FUNCTION__), 0 : 0))
;
4094 gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE)((void)(!(((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4094, __FUNCTION__, (BLOCK)))->block.supercontext) == (tree
) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4094, __FUNCTION__), 0 : 0))
;
4095 gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE)((void)(!(((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4095, __FUNCTION__, (BLOCK)))->block.chain) == (tree) nullptr
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4095, __FUNCTION__), 0 : 0))
;
4096 /* Replace the top block to avoid issues with locations for args
4097 appearing to be in a non-existent place. */
4098 tree replace_blk = make_node (BLOCK);
4099 BLOCK_VARS (replace_blk)((tree_check ((replace_blk), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4099, __FUNCTION__, (BLOCK)))->block.vars)
= BLOCK_VARS (block)((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4099, __FUNCTION__, (BLOCK)))->block.vars)
;
4100 BLOCK_SUBBLOCKS (replace_blk)((tree_check ((replace_blk), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4100, __FUNCTION__, (BLOCK)))->block.subblocks)
= BLOCK_SUBBLOCKS (block)((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4100, __FUNCTION__, (BLOCK)))->block.subblocks)
;
4101 for (tree b = BLOCK_SUBBLOCKS (replace_blk)((tree_check ((replace_blk), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4101, __FUNCTION__, (BLOCK)))->block.subblocks)
; b; b = BLOCK_CHAIN (b)((tree_check ((b), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4101, __FUNCTION__, (BLOCK)))->block.chain)
)
4102 BLOCK_SUPERCONTEXT (b)((tree_check ((b), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4102, __FUNCTION__, (BLOCK)))->block.supercontext)
= replace_blk;
4103 BIND_EXPR_BLOCK (first)((*((const_cast<tree*> (tree_operand_check (((tree_check
((first), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4103, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4103, __FUNCTION__))))))
= replace_blk;
4104 /* The top block has one child, so far, and we have now got a
4105 superblock. */
4106 BLOCK_SUPERCONTEXT (replace_blk)((tree_check ((replace_blk), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4106, __FUNCTION__, (BLOCK)))->block.supercontext)
= top_block;
4107 BLOCK_SUBBLOCKS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4107, __FUNCTION__, (BLOCK)))->block.subblocks)
= replace_blk;
4108 }
4109 else
4110 {
4111 /* We are missing a top level BIND_EXPR. We need one to ensure that we
4112 don't shuffle around the coroutine frame and corrupt it. */
4113 tree bind_wrap = build3_loc (fn_start, BIND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE],
4114 NULLnullptr, NULLnullptr, NULLnullptr);
4115 BIND_EXPR_BODY (bind_wrap)((*((const_cast<tree*> (tree_operand_check (((tree_check
((bind_wrap), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4115, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4115, __FUNCTION__))))))
= fnbody;
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(tree) nullptr;
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(tree) nullptr);
4135 DECL_CHAIN (resume_fn_ptr)(((contains_struct_check (((contains_struct_check ((resume_fn_ptr
), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4135, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4135, __FUNCTION__))->common.chain))
= 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_nodec_global_trees[CTI_NULLPTR]);
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(tree) nullptr);
4147 DECL_CHAIN (var)(((contains_struct_check (((contains_struct_check ((var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4147, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4147, __FUNCTION__))->common.chain))
= 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)((contains_struct_check ((promise), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4154, __FUNCTION__))->decl_minimal.context)
= orig;
4155 DECL_SOURCE_LOCATION (promise)((contains_struct_check ((promise), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4155, __FUNCTION__))->decl_minimal.locus)
= fn_start;
4156 DECL_CHAIN (promise)(((contains_struct_check (((contains_struct_check ((promise),
(TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4156, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4156, __FUNCTION__))->common.chain))
= 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)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4164, __FUNCTION__))->decl_minimal.context)
= orig;
4165 DECL_SOURCE_LOCATION (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4165, __FUNCTION__))->decl_minimal.locus)
= fn_start;
4166 DECL_CHAIN (var)(((contains_struct_check (((contains_struct_check ((var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4166, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4166, __FUNCTION__))->common.chain))
= 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))((void)(!(((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4177, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4177, __FUNCTION__), 0 : 0))
;
4178 /* Add a local var for each parm. */
4179 for (tree arg = DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4179, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr;
4180 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4180, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4180, __FUNCTION__))->common.chain))
)
4181 {
4182 param_info *parm_i = param_uses->get (arg);
4183 gcc_checking_assert (parm_i)((void)(!(parm_i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4183, __FUNCTION__), 0 : 0))
;
4184 parm_i->copy_var
4185 = build_lang_decl (VAR_DECL, parm_i->field_id, TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4185, __FUNCTION__))->typed.type)
);
4186 DECL_SOURCE_LOCATION (parm_i->copy_var)((contains_struct_check ((parm_i->copy_var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4186, __FUNCTION__))->decl_minimal.locus)
= DECL_SOURCE_LOCATION (arg)((contains_struct_check ((arg), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4186, __FUNCTION__))->decl_minimal.locus)
;
4187 DECL_CONTEXT (parm_i->copy_var)((contains_struct_check ((parm_i->copy_var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4187, __FUNCTION__))->decl_minimal.context)
= orig;
4188 DECL_ARTIFICIAL (parm_i->copy_var)((contains_struct_check ((parm_i->copy_var), (TS_DECL_COMMON
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4188, __FUNCTION__))->decl_common.artificial_flag)
= true;
4189 DECL_CHAIN (parm_i->copy_var)(((contains_struct_check (((contains_struct_check ((parm_i->
copy_var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4189, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4189, __FUNCTION__))->common.chain))
= 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 = {NULLnullptr, param_uses,
4200 &visited, fn_start, false};
4201 cp_walk_tree (&fnbody, rewrite_param_uses, &param_data, NULL)walk_tree_1 (&fnbody, rewrite_param_uses, &param_data
, nullptr, cp_walk_subtrees)
;
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_nodeinteger_types[itk_unsigned_short], orig, NULL_TREE(tree) nullptr);
4208 DECL_CHAIN (resume_idx_var)(((contains_struct_check (((contains_struct_check ((resume_idx_var
), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4208, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4208, __FUNCTION__))->common.chain))
= 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_nodeglobal_trees[TI_BOOLEAN_TYPE], orig, NULL_TREE(tree) nullptr);
4216 DECL_CHAIN (var)(((contains_struct_check (((contains_struct_check ((var), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4216, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4216, __FUNCTION__))->common.chain))
= var_list;
4217 var_list = var;
4218 add_decl_expr (var);
4219
4220 if (flag_exceptionsglobal_options.x_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, NULLnullptr, /*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_nodeglobal_trees[TI_BOOLEAN_TYPE], orig,
4232 boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE]);
4233 DECL_CHAIN (i_a_r_c)(((contains_struct_check (((contains_struct_check ((i_a_r_c),
(TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4233, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4233, __FUNCTION__))->common.chain))
= 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(tree) nullptr, NULL_TREE(tree) nullptr);
4238 add_stmt (tcb);
4239 TRY_STMTS (tcb)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4239, __FUNCTION__, (TRY_BLOCK)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4239, __FUNCTION__)))))
= push_stmt_list ();
4240 if (initial_await != error_mark_nodeglobal_trees[TI_ERROR_MARK])
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)(((enum tree_code) (initial_await)->base.code) == INDIRECT_REF
)
)
4249 initial_await = TREE_OPERAND (initial_await, 0)(*((const_cast<tree*> (tree_operand_check ((initial_await
), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4249, __FUNCTION__)))))
;
4250 tree vec = TREE_OPERAND (initial_await, 3)(*((const_cast<tree*> (tree_operand_check ((initial_await
), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4250, __FUNCTION__)))))
;
4251 tree aw_r = TREE_VEC_ELT (vec, 2)(*((const_cast<tree *> (tree_vec_elt_check ((vec), (2),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4251, __FUNCTION__)))))
;
4252 aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error);
4253 tree update = build2 (MODIFY_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], i_a_r_c,
4254 boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE]);
4255 aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error);
4256 TREE_VEC_ELT (vec, 2)(*((const_cast<tree *> (tree_vec_elt_check ((vec), (2),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4256, __FUNCTION__)))))
= 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)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4264, __FUNCTION__, (TRY_BLOCK)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4264, __FUNCTION__)))))
= pop_stmt_list (TRY_STMTS (tcb)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4264, __FUNCTION__, (TRY_BLOCK)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4264, __FUNCTION__)))))
);
4265 TRY_HANDLERS (tcb)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4265, __FUNCTION__, (TRY_BLOCK)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4265, __FUNCTION__)))))
= push_stmt_list ();
4266 /* Mimic what the parser does for the catch. */
4267 tree handler = begin_handler ();
4268 finish_handler_parms (NULL_TREE(tree) nullptr, 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_nodeglobal_trees[TI_BOOLEAN_TYPE], 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(tree) nullptr);
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)(*((const_cast<tree*> (tree_operand_check (((tree_check
((not_iarc_if), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4280, __FUNCTION__, (IF_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4280, __FUNCTION__)))))
;
4281 IF_SCOPE (not_iarc_if)(*((const_cast<tree*> (tree_operand_check (((tree_check
((not_iarc_if), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4281, __FUNCTION__, (IF_STMT)))), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4281, __FUNCTION__)))))
= NULLnullptr;
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_nodeinteger_types[itk_unsigned_short], 0);
4293 r = build2 (MODIFY_EXPR, short_unsigned_type_nodeinteger_types[itk_unsigned_short], resume_idx_var,
4294 short_zero);
4295 finish_expr_stmt (r);
4296 finish_expr_stmt (ueh);
4297 finish_handler (handler);
4298 TRY_HANDLERS (tcb)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4298, __FUNCTION__, (TRY_BLOCK)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4298, __FUNCTION__)))))
= pop_stmt_list (TRY_HANDLERS (tcb)(*((const_cast<tree*> (tree_operand_check (((tree_check
((tcb), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4298, __FUNCTION__, (TRY_BLOCK)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4298, __FUNCTION__)))))
);
4299 }
4300 else
4301 {
4302 if (pedanticglobal_options.x_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_nodeglobal_trees[TI_ERROR_MARK])
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(tree) nullptr);
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)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4335, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4335, __FUNCTION__))))))
= pop_stmt_list (BIND_EXPR_BODY (update_body)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4335, __FUNCTION__, (BIND_EXPR)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4335, __FUNCTION__))))))
);
4336 BIND_EXPR_VARS (update_body)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4336, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4336, __FUNCTION__))))))
= nreverse (var_list);
4337 BLOCK_VARS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4337, __FUNCTION__, (BLOCK)))->block.vars)
= BIND_EXPR_VARS (update_body)((*((const_cast<tree*> (tree_operand_check (((tree_check
((update_body), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4337, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4337, __FUNCTION__))))))
;
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
4372bool
4373morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
4374{
4375 gcc_checking_assert (orig && TREE_CODE (orig) == FUNCTION_DECL)((void)(!(orig && ((enum tree_code) (orig)->base.code
) == FUNCTION_DECL) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4375, __FUNCTION__), 0 : 0))
;
4376
4377 *resumer = error_mark_nodeglobal_trees[TI_ERROR_MARK];
4378 *destroyer = error_mark_nodeglobal_trees[TI_ERROR_MARK];
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)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4386, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
);
4387 DECL_SAVED_TREE (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4387, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
= 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)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4393, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
);
4394 gcc_checking_assert (fnbody != NULL_TREE)((void)(!(fnbody != (tree) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4394, __FUNCTION__), 0 : 0))
;
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)((contains_struct_check ((orig), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4399, __FUNCTION__))->decl_minimal.locus)
;
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(tree) nullptr || body_start == error_mark_nodeglobal_trees[TI_ERROR_MARK])
4406 {
4407 DECL_SAVED_TREE (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4407, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
= push_stmt_list ();
4408 append_to_statement_list (fnbody, &DECL_SAVED_TREE (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4408, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
);
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)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4424, __FUNCTION__, (FUNCTION_DECL)))->function_decl.saved_tree
)
= 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)((enum tree_code) (body_start)->base.code) == 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)(*((const_cast<tree*> (tree_operand_check ((body_start)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4433, __FUNCTION__)))))
;
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)(*((const_cast<tree*> (tree_operand_check ((body_start)
, (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4437, __FUNCTION__)))))
= 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((cfun + 0)->language)->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))((contains_struct_check ((((contains_struct_check ((orig), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4454, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4454, __FUNCTION__))->typed.type)
;
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))((contains_struct_check ((((tree_class_check ((coro_frame_type
), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4462, __FUNCTION__))->type_common.name)), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4462, __FUNCTION__))->decl_minimal.context)
= 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_nodeglobal_trees[TI_VOID_TYPE], coro_frame_ptr, NULL_TREE(tree) nullptr);
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(tree) nullptr;
4478 tree fs_label = NULL_TREE(tree) nullptr;
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(tree) nullptr;
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, NULLnullptr, NULLnullptr, 0, 0,
4500 hash_set<tree> (), NULLnullptr, NULLnullptr, 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)walk_tree_1 (&fnbody, await_statement_walker, &body_aw_points
, nullptr, cp_walk_subtrees)
;
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)walk_tree_1 (&fnbody, register_local_var_uses, &local_vars_data
, nullptr, cp_walk_subtrees)
;
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)((tree_check3 ((coro_frame_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4515, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))->type_non_common.values)
= field_list;
4516 TYPE_BINFO (coro_frame_type)((tree_check3 ((coro_frame_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4516, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))->type_non_common.maxval)
= make_tree_binfo (0);
4517 BINFO_OFFSET (TYPE_BINFO (coro_frame_type))((tree_check ((((tree_check3 ((coro_frame_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4517, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))->type_non_common.maxval)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4517, __FUNCTION__, (TREE_BINFO)))->binfo.offset)
= size_zero_nodeglobal_trees[TI_SIZE_ZERO];
4518 BINFO_TYPE (TYPE_BINFO (coro_frame_type))((contains_struct_check (((tree_check ((((tree_check3 ((coro_frame_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4518, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE
)))->type_non_common.maxval)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4518, __FUNCTION__, (TREE_BINFO)))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4518, __FUNCTION__))->typed.type)
= coro_frame_type;
4519
4520 coro_frame_type = finish_struct (coro_frame_type, NULL_TREE(tree) nullptr);
4521
4522 /* Ramp: */
4523 /* Now build the ramp function pieces. */
4524 tree ramp_bind = build3 (BIND_EXPR, void_type_nodeglobal_trees[TI_VOID_TYPE], NULLnullptr, NULLnullptr, NULLnullptr);
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_nodec_global_trees[CTI_NULLPTR]);
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_exceptionsglobal_options.x_flag_exceptions && DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4535, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
)
4536 for (tree arg = DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4536, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr;
4537 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4537, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4537, __FUNCTION__))->common.chain))
)
4538 {
4539 param_info *parm_i = param_uses->get (arg);
4540 gcc_checking_assert (parm_i)((void)(!(parm_i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4540, __FUNCTION__), 0 : 0))
;
4541 if (parm_i->trivial_dtor)
4542 continue;
4543 DECL_CHAIN (parm_i->guard_var)(((contains_struct_check (((contains_struct_check ((parm_i->
guard_var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4543, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4543, __FUNCTION__))->common.chain))
= 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_nodeglobal_trees[TI_BOOLEAN_TYPE], orig, boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE]);
4551 DECL_CHAIN (coro_promise_live)(((contains_struct_check (((contains_struct_check ((coro_promise_live
), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4551, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4551, __FUNCTION__))->common.chain))
= 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_nodeglobal_trees[TI_BOOLEAN_TYPE], orig, boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE]);
4559
4560 DECL_CHAIN (coro_gro_live)(((contains_struct_check (((contains_struct_check ((coro_gro_live
), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4560, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4560, __FUNCTION__))->common.chain))
= varlist;
4561 varlist = coro_gro_live;
4562
4563 /* Collected the scope vars we need ... only one for now. */
4564 BIND_EXPR_VARS (ramp_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((ramp_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4564, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4564, __FUNCTION__))))))
= 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)((*((const_cast<tree*> (tree_operand_check (((tree_check
((ramp_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4570, __FUNCTION__, (BIND_EXPR)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4570, __FUNCTION__))))))
= top_block;
4571 BLOCK_VARS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4571, __FUNCTION__, (BLOCK)))->block.vars)
= BIND_EXPR_VARS (ramp_bind)((*((const_cast<tree*> (tree_operand_check (((tree_check
((ramp_bind), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4571, __FUNCTION__, (BIND_EXPR)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4571, __FUNCTION__))))))
;
4572 BLOCK_SUBBLOCKS (top_block)((tree_check ((top_block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4572, __FUNCTION__, (BLOCK)))->block.subblocks)
= NULL_TREE(tree) nullptr;
4573 current_binding_level(*((cfun + 0) && ((cfun + 0)->language) &&
((cfun + 0)->language)->bindings ? &((cfun + 0)->
language)->bindings : &scope_chain->bindings))
->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_exceptionsglobal_options.x_flag_exceptions && DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4580, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
)
4581 for (tree arg = DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4581, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr;
4582 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4582, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4582, __FUNCTION__))->common.chain))
)
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)((tree_class_check ((coro_frame_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4596, __FUNCTION__))->type_common.size_unit)
;
4597 tree resizeable
4598 = build_call_expr_internal_loc (fn_start, IFN_CO_FRAME, size_type_nodeglobal_trees[TI_SIZE_TYPE], 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, NULLnullptr, /*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_nodeglobal_trees[TI_ERROR_MARK])
4617 grooaf = NULL_TREE(tree) nullptr;
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(tree) nullptr;
4626
4627 if (TYPE_HAS_NEW_OPERATOR (promise_type)((((tree_class_check ((promise_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4627, __FUNCTION__))->type_with_lang_specific.lang_specific
))->has_new)
)
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)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4640, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr;
4641 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4641, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4641, __FUNCTION__))->common.chain))
)
4642 {
4643 param_info *parm_i = param_uses->get (arg);
4644 gcc_checking_assert (parm_i)((void)(!(parm_i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4644, __FUNCTION__), 0 : 0))
;
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))((contains_struct_check ((((contains_struct_check ((arg), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4648, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4648, __FUNCTION__))->typed.type)
;
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_STATIC2,
4652 LOOKUP_NORMAL((1 << 0)) , NULL_TREE(tree) nullptr,
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, NULLnullptr,
4664 LOOKUP_NORMAL((1 << 0)), &func, tf_none);
4665 release_tree_vector (args);
4666
4667 if (new_fn == error_mark_nodeglobal_trees[TI_ERROR_MARK])
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(tree) nullptr, LOOKUP_NORMAL((1 << 0)), &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_nodeglobal_trees[TI_ERROR_MARK])
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_nodeglobal_trees[TI_ERROR_MARK];
4687 }
4688 else if (grooaf && !TYPE_NOTHROW_P (TREE_TYPE (func))nothrow_spec_p (((tree_class_check (((tree_check2 ((((contains_struct_check
((func), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4688, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4688, __FUNCTION__, (FUNCTION_TYPE), (METHOD_TYPE)))), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4688, __FUNCTION__))->type_non_common.lang_1))
)
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))nothrow_spec_p (((tree_class_check (((tree_check2 ((((contains_struct_check
((func), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4691, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4691, __FUNCTION__, (FUNCTION_TYPE), (METHOD_TYPE)))), (tcc_type
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4691, __FUNCTION__))->type_non_common.lang_1))
)
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_nodecp_global_trees[CPTI_STD],
4717 get_identifier ("nothrow")(__builtin_constant_p ("nothrow") ? get_identifier_with_length
(("nothrow"), strlen ("nothrow")) : get_identifier ("nothrow"
))
,
4718 LOOK_want::NORMAL,
4719 /*complain=*/true);
4720 if (!std_nt || std_nt == error_mark_nodeglobal_trees[TI_ERROR_MARK])
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 = NULLnullptr;
4731 new_fn = build_operator_new_call (nwname, &args, &frame_size, &cookie,
4732 /*align_arg=*/NULLnullptr,
4733 /*size_check=*/NULLnullptr, /*fn=*/NULLnullptr,
4734 tf_warning_or_error);
4735 resizeable = build_call_expr_internal_loc
4736 (fn_start, IFN_CO_FRAME, size_type_nodeglobal_trees[TI_SIZE_TYPE], 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_nodeglobal_trees[TI_ERROR_MARK])
4740 CALL_EXPR_ARG (new_fn, 0)(*((const_cast<tree*> (tree_operand_check (((tree_check
((new_fn), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4740, __FUNCTION__, (CALL_EXPR)))), ((0) + 3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4740, __FUNCTION__)))))
= resizeable;
4741
4742 release_tree_vector (args);
4743 }
4744
4745 tree allocated = build1 (CONVERT_EXPR, coro_frame_ptr, new_fn);
4746 tree r = cp_build_init_expr (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)))((void)(!(comptypes ((fn_return_type), (((contains_struct_check
((grooaf), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4762, __FUNCTION__))->typed.type)), 0)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4762, __FUNCTION__), 0 : 0))
;
4763 tree if_stmt = begin_if_stmt ();
4764 tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, nullptr_nodec_global_trees[CTI_NULLPTR]);
4765 cond = build2 (EQ_EXPR, boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], coro_fp, cond);
4766 finish_if_stmt_cond (cond, if_stmt);
4767 if (VOID_TYPE_P (fn_return_type)(((enum tree_code) (fn_return_type)->base.code) == VOID_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(tree) nullptr);
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(tree) nullptr;
4791 if (flag_exceptionsglobal_options.x_flag_exceptions)
4792 {
4793 ramp_cleanup = build_stmt (fn_start, TRY_BLOCK, NULLnullptr, NULLnullptr);
4794 add_stmt (ramp_cleanup);
4795 TRY_STMTS (ramp_cleanup)(*((const_cast<tree*> (tree_operand_check (((tree_check
((ramp_cleanup), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4795, __FUNCTION__, (TRY_BLOCK)))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4795, __FUNCTION__)))))
= 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(tree) nullptr,
4806 false, tf_warning_or_error);
4807 r = cp_build_init_expr (fnf_x, boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE]);
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(tree) nullptr,
4818 false, tf_warning_or_error);
4819 r = cp_build_init_expr (fn_start, 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(tree) nullptr, false,
4828 tf_warning_or_error);
4829 r = cp_build_init_expr (fn_start, 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 = NULLnullptr; /* 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 = NULLnullptr;
4851
4852 if (DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4852, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
)
4853 {
4854 promise_args = make_tree_vector ();
4855 for (tree arg = DECL_ARGUMENTS (orig)((tree_check ((orig), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4855, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments
)
; arg != NULLnullptr;
4856 arg = DECL_CHAIN (arg)(((contains_struct_check (((contains_struct_check ((arg), (TS_DECL_MINIMAL
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4856, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4856, __FUNCTION__))->common.chain))
)
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(tree) nullptr,
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)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4873, __FUNCTION__))->typed.type)
;
4874 gcc_checking_assert (POINTER_TYPE_P (tt))((void)(!((((enum tree_code) (tt)->base.code) == POINTER_TYPE
|| ((enum tree_code) (tt)->base.code) == REFERENCE_TYPE))
? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4874, __FUNCTION__), 0 : 0))
;
4875 tree ct = TREE_TYPE (tt)((contains_struct_check ((tt), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/cp/coroutines.cc"
, 4875, __FUNCTION__))->typed.type)
;
487