File: | build/gcc/cp/coroutines.cc |
Warning: | line 1363, column 8 Value stored to 'co_ret_call' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* coroutine-specific state, expansions and tests. |
2 | |
3 | Copyright (C) 2018-2023 Free Software Foundation, Inc. |
4 | |
5 | Contributed by Iain Sandoe <iain@sandoe.co.uk> under contract to Facebook. |
6 | |
7 | This file is part of GCC. |
8 | |
9 | GCC is free software; you can redistribute it and/or modify it under |
10 | the terms of the GNU General Public License as published by the Free |
11 | Software Foundation; either version 3, or (at your option) any later |
12 | version. |
13 | |
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
17 | for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with GCC; see the file COPYING3. If not see |
21 | <http://www.gnu.org/licenses/>. */ |
22 | |
23 | #include "config.h" |
24 | #include "system.h" |
25 | #include "coretypes.h" |
26 | #include "target.h" |
27 | #include "cp-tree.h" |
28 | #include "stringpool.h" |
29 | #include "stmt.h" |
30 | #include "stor-layout.h" |
31 | #include "tree-iterator.h" |
32 | #include "tree.h" |
33 | #include "gcc-rich-location.h" |
34 | #include "hash-map.h" |
35 | |
36 | static bool coro_promise_type_found_p (tree, location_t); |
37 | |
38 | /* GCC C++ coroutines implementation. |
39 | |
40 | The user authors a function that becomes a coroutine (lazily) by |
41 | making use of any of the co_await, co_yield or co_return keywords. |
42 | |
43 | Unlike a regular function, where the activation record is placed on the |
44 | stack, and is destroyed on function exit, a coroutine has some state that |
45 | persists between calls - the coroutine frame (analogous to a stack frame). |
46 | |
47 | We transform the user's function into three pieces: |
48 | 1. A so-called ramp function, that establishes the coroutine frame and |
49 | begins execution of the coroutine. |
50 | 2. An actor function that contains the state machine corresponding to the |
51 | user's suspend/resume structure. |
52 | 3. A stub function that calls the actor function in 'destroy' mode. |
53 | |
54 | The actor function is executed: |
55 | * from "resume point 0" by the ramp. |
56 | * from resume point N ( > 0 ) for handle.resume() calls. |
57 | * from the destroy stub for destroy point N for handle.destroy() calls. |
58 | |
59 | The functions in this file carry out the necessary analysis of, and |
60 | transforms to, the AST to perform this. |
61 | |
62 | The C++ coroutine design makes use of some helper functions that are |
63 | authored in a so-called "promise" class provided by the user. |
64 | |
65 | At parse time (or post substitution) the type of the coroutine promise |
66 | will be determined. At that point, we can look up the required promise |
67 | class methods and issue diagnostics if they are missing or incorrect. To |
68 | avoid repeating these actions at code-gen time, we make use of temporary |
69 | 'proxy' variables for the coroutine handle and the promise - which will |
70 | eventually be instantiated in the coroutine frame. |
71 | |
72 | Each of the keywords will expand to a code sequence (although co_yield is |
73 | just syntactic sugar for a co_await). |
74 | |
75 | We defer the analysis and transformation until template expansion is |
76 | complete so that we have complete types at that time. */ |
77 | |
78 | |
79 | /* The state that we collect during parsing (and template expansion) for |
80 | a coroutine. */ |
81 | |
82 | struct GTY((for_user)) coroutine_info |
83 | { |
84 | tree function_decl; /* The original function decl. */ |
85 | tree actor_decl; /* The synthesized actor function. */ |
86 | tree destroy_decl; /* The synthesized destroy function. */ |
87 | tree promise_type; /* The cached promise type for this function. */ |
88 | tree handle_type; /* The cached coroutine handle for this function. */ |
89 | tree self_h_proxy; /* A handle instance that is used as the proxy for the |
90 | one that will eventually be allocated in the coroutine |
91 | frame. */ |
92 | tree promise_proxy; /* Likewise, a proxy promise instance. */ |
93 | tree return_void; /* The expression for p.return_void() if it exists. */ |
94 | location_t first_coro_keyword; /* The location of the keyword that made this |
95 | function into a coroutine. */ |
96 | /* Flags to avoid repeated errors for per-function issues. */ |
97 | bool coro_ret_type_error_emitted; |
98 | bool coro_promise_error_emitted; |
99 | bool coro_co_return_error_emitted; |
100 | }; |
101 | |
102 | struct coroutine_info_hasher : ggc_ptr_hash<coroutine_info> |
103 | { |
104 | typedef tree compare_type; /* We only compare the function decl. */ |
105 | static inline hashval_t hash (coroutine_info *); |
106 | static inline hashval_t hash (const compare_type &); |
107 | static inline bool equal (coroutine_info *, coroutine_info *); |
108 | static inline bool equal (coroutine_info *, const compare_type &); |
109 | }; |
110 | |
111 | /* This table holds all the collected coroutine state for coroutines in |
112 | the current translation unit. */ |
113 | |
114 | static GTY (()) hash_table<coroutine_info_hasher> *coroutine_info_table; |
115 | |
116 | /* We will initialize state lazily. */ |
117 | static bool coro_initialized = false; |
118 | |
119 | /* Return a hash value for the entry pointed to by INFO. |
120 | The compare type is a tree, but the only trees we are going use are |
121 | function decls. We use the DECL_UID as the hash value since that is |
122 | stable across PCH. */ |
123 | |
124 | hashval_t |
125 | coroutine_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 | |
132 | hashval_t |
133 | coroutine_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 | |
141 | bool |
142 | coroutine_info_hasher::equal (coroutine_info *lhs, coroutine_info *rhs) |
143 | { |
144 | return lhs->function_decl == rhs->function_decl; |
145 | } |
146 | |
147 | bool |
148 | coroutine_info_hasher::equal (coroutine_info *lhs, const compare_type& rhs) |
149 | { |
150 | return lhs->function_decl == rhs; |
151 | } |
152 | |
153 | /* Get the existing coroutine_info for FN_DECL, or insert a new one if the |
154 | entry does not yet exist. */ |
155 | |
156 | coroutine_info * |
157 | get_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 | |
175 | coroutine_info * |
176 | get_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 | |
193 | static GTY(()) tree coro_traits_identifier; |
194 | static GTY(()) tree coro_handle_identifier; |
195 | static GTY(()) tree coro_promise_type_identifier; |
196 | |
197 | /* Required promise method name identifiers. */ |
198 | |
199 | static GTY(()) tree coro_await_transform_identifier; |
200 | static GTY(()) tree coro_initial_suspend_identifier; |
201 | static GTY(()) tree coro_final_suspend_identifier; |
202 | static GTY(()) tree coro_return_void_identifier; |
203 | static GTY(()) tree coro_return_value_identifier; |
204 | static GTY(()) tree coro_yield_value_identifier; |
205 | static GTY(()) tree coro_resume_identifier; |
206 | static GTY(()) tree coro_address_identifier; |
207 | static GTY(()) tree coro_from_address_identifier; |
208 | static GTY(()) tree coro_get_return_object_identifier; |
209 | static GTY(()) tree coro_gro_on_allocation_fail_identifier; |
210 | static GTY(()) tree coro_unhandled_exception_identifier; |
211 | |
212 | /* Awaitable methods. */ |
213 | |
214 | static GTY(()) tree coro_await_ready_identifier; |
215 | static GTY(()) tree coro_await_suspend_identifier; |
216 | static GTY(()) tree coro_await_resume_identifier; |
217 | |
218 | /* Accessors for the coroutine frame state used by the implementation. */ |
219 | |
220 | static GTY(()) tree coro_resume_fn_id; |
221 | static GTY(()) tree coro_destroy_fn_id; |
222 | static GTY(()) tree coro_promise_id; |
223 | static GTY(()) tree coro_frame_needs_free_id; |
224 | static GTY(()) tree coro_resume_index_id; |
225 | static GTY(()) tree coro_self_handle_id; |
226 | static GTY(()) tree coro_actor_continue_id; |
227 | static GTY(()) tree coro_frame_i_a_r_c_id; |
228 | |
229 | /* Create the identifiers used by the coroutines library interfaces and |
230 | the implementation frame state. */ |
231 | |
232 | static void |
233 | coro_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 | |
270 | static GTY(()) tree coro_traits_templ; |
271 | static GTY(()) tree coro_handle_templ; |
272 | static GTY(()) tree void_coro_handle_type; |
273 | |
274 | /* ================= Parse, Semantics and Type checking ================= */ |
275 | |
276 | /* This initial set of routines are helper for the parsing and template |
277 | expansion phases. |
278 | |
279 | At the completion of this, we will have completed trees for each of the |
280 | keywords, but making use of proxy variables for the self-handle and the |
281 | promise class instance. */ |
282 | |
283 | /* [coroutine.traits] |
284 | Lookup the coroutine_traits template decl. */ |
285 | |
286 | static tree |
287 | find_coro_traits_template_decl (location_t kw) |
288 | { |
289 | /* If we are missing fundamental information, such as the traits, (or the |
290 | declaration found is not a type template), then don't emit an error for |
291 | every keyword in a TU, just do it once. */ |
292 | static bool traits_error_emitted = false; |
293 | |
294 | tree traits_decl = lookup_qualified_name (std_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 | |
316 | static tree |
317 | instantiate_coro_traits (tree fndecl, location_t kw) |
318 | { |
319 | /* [coroutine.traits.primary] |
320 | So now build up a type list for the template <typename _R, typename...>. |
321 | The types are the function's arg types and _R is the function return |
322 | type. */ |
323 | |
324 | tree functyp = TREE_TYPE (fndecl)((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 | |
369 | static tree |
370 | find_coro_handle_template_decl (location_t kw) |
371 | { |
372 | /* As for the coroutine traits, this error is per TU, so only emit |
373 | it once. */ |
374 | static bool coro_handle_error_emitted = false; |
375 | tree handle_decl = lookup_qualified_name (std_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 | |
393 | static tree |
394 | instantiate_coro_handle_for_promise_type (location_t kw, tree promise_type) |
395 | { |
396 | /* So now build up a type list for the template, one entry, the promise. */ |
397 | tree targ = make_tree_vec (1); |
398 | TREE_VEC_ELT (targ, 0)(*((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 | |
417 | static tree |
418 | find_promise_type (tree traits_class) |
419 | { |
420 | tree promise_type |
421 | = lookup_member (traits_class, coro_promise_type_identifier, |
422 | /* protect=*/1, /*want_type=*/true, tf_warning_or_error); |
423 | |
424 | if (promise_type) |
425 | promise_type |
426 | = complete_type_or_else (TREE_TYPE (promise_type)((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 | |
432 | static bool |
433 | coro_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. */ |
560 | static GTY(()) hash_map<tree, tree> *to_ramp; |
561 | |
562 | /* Given a tree that is an actor or destroy, find the ramp function. */ |
563 | |
564 | tree |
565 | coro_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 | |
578 | tree |
579 | coro_get_actor_function (tree decl) |
580 | { |
581 | if (coroutine_info *info = get_coroutine_info (decl)) |
582 | return info->actor_decl; |
583 | |
584 | return NULL_TREE(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 | |
590 | tree |
591 | coro_get_destroy_function (tree decl) |
592 | { |
593 | if (coroutine_info *info = get_coroutine_info (decl)) |
594 | return info->destroy_decl; |
595 | |
596 | return NULL_TREE(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 | |
602 | static tree |
603 | get_coroutine_promise_type (tree decl) |
604 | { |
605 | if (coroutine_info *info = get_coroutine_info (decl)) |
606 | return info->promise_type; |
607 | |
608 | return NULL_TREE(tree) nullptr; |
609 | } |
610 | |
611 | static tree |
612 | get_coroutine_handle_type (tree decl) |
613 | { |
614 | if (coroutine_info *info = get_coroutine_info (decl)) |
615 | return info->handle_type; |
616 | |
617 | return NULL_TREE(tree) nullptr; |
618 | } |
619 | |
620 | static tree |
621 | get_coroutine_self_handle_proxy (tree decl) |
622 | { |
623 | if (coroutine_info *info = get_coroutine_info (decl)) |
624 | return info->self_h_proxy; |
625 | |
626 | return NULL_TREE(tree) nullptr; |
627 | } |
628 | |
629 | static tree |
630 | get_coroutine_promise_proxy (tree decl) |
631 | { |
632 | if (coroutine_info *info = get_coroutine_info (decl)) |
633 | return info->promise_proxy; |
634 | |
635 | return NULL_TREE(tree) nullptr; |
636 | } |
637 | |
638 | static tree |
639 | lookup_promise_method (tree fndecl, tree member_id, location_t loc, |
640 | bool musthave) |
641 | { |
642 | tree promise = get_coroutine_promise_type (fndecl); |
643 | tree pm_memb |
644 | = lookup_member (promise, member_id, |
645 | /*protect=*/1, /*want_type=*/0, tf_warning_or_error); |
646 | if (musthave && pm_memb == NULL_TREE(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 | |
660 | static tree |
661 | coro_build_promise_expression (tree fn, tree promise_obj, tree member_id, |
662 | location_t loc, vec<tree, va_gc> **args, |
663 | bool musthave) |
664 | { |
665 | tree meth = lookup_promise_method (fn, member_id, loc, musthave); |
666 | if (meth == error_mark_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 | |
696 | static tree |
697 | get_coroutine_return_void_expr (tree decl, location_t loc, bool musthave) |
698 | { |
699 | if (coroutine_info *info = get_coroutine_info (decl)) |
700 | { |
701 | /* If we don't have it try to build it. */ |
702 | if (!info->return_void) |
703 | info->return_void |
704 | = coro_build_promise_expression (current_function_decl, 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 | |
718 | static tree |
719 | lookup_awaitable_member (tree await_type, tree member_id, location_t loc) |
720 | { |
721 | tree aw_memb |
722 | = lookup_member (await_type, member_id, |
723 | /*protect=*/1, /*want_type=*/0, tf_warning_or_error); |
724 | if (aw_memb == NULL_TREE(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 | |
735 | static bool |
736 | coro_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__); <->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 | |
805 | static bool |
806 | coro_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 | |
835 | enum suspend_point_kind { |
836 | CO_AWAIT_SUSPEND_POINT = 0, |
837 | CO_YIELD_SUSPEND_POINT, |
838 | INITIAL_SUSPEND_POINT, |
839 | FINAL_SUSPEND_POINT |
840 | }; |
841 | |
842 | /* Helper function to build a named variable for the temps we use for each |
843 | await point. The root of the name is determined by SUSPEND_KIND, and |
844 | the variable is of type V_TYPE. The awaitable number is reset each time |
845 | we encounter a final suspend. */ |
846 | |
847 | static tree |
848 | get_awaitable_var (suspend_point_kind suspend_kind, tree v_type) |
849 | { |
850 | static int awn = 0; |
851 | char *buf; |
852 | switch (suspend_kind) |
853 | { |
854 | default: buf = xasprintf ("Aw%d", awn++); break; |
855 | case CO_YIELD_SUSPEND_POINT: buf = xasprintf ("Yd%d", awn++); break; |
856 | case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break; |
857 | case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); awn = 0; break; |
858 | } |
859 | tree ret = get_identifier (buf)(__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 | |
868 | static bool |
869 | coro_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 | |
883 | static bool |
884 | coro_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 | |
914 | static tree |
915 | build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) |
916 | { |
917 | /* Try and overload of operator co_await, .... */ |
918 | tree o; |
919 | if (MAYBE_CLASS_TYPE_P (TREE_TYPE (a))((((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__); <->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 | |
1146 | tree |
1147 | finish_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__); <->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 | |
1222 | tree |
1223 | finish_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__); <->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 | |
1297 | tree |
1298 | finish_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__); <->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 | |
1403 | tree |
1404 | coro_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 | |
1503 | static tree |
1504 | coro_build_expr_stmt (tree expr, location_t loc) |
1505 | { |
1506 | return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr)); |
1507 | } |
1508 | |
1509 | static tree |
1510 | coro_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 | |
1519 | static tree |
1520 | coro_build_artificial_var (location_t loc, tree name, tree type, tree ctx, |
1521 | tree init) |
1522 | { |
1523 | tree res = build_lang_decl (VAR_DECL, name, type); |
1524 | DECL_SOURCE_LOCATION (res)((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 | |
1531 | static tree |
1532 | coro_build_artificial_var (location_t loc, const char *name, tree type, |
1533 | tree ctx, tree init) |
1534 | { |
1535 | return coro_build_artificial_var (loc, get_identifier (name)(__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 | |
1542 | static tree |
1543 | create_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 | |
1556 | static tree |
1557 | create_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 | |
1567 | struct proxy_replace |
1568 | { |
1569 | tree from, to; |
1570 | }; |
1571 | |
1572 | static tree |
1573 | replace_proxy (tree *here, int *do_subtree, void *d) |
1574 | { |
1575 | proxy_replace *data = (proxy_replace *) d; |
1576 | |
1577 | if (*here == data->from) |
1578 | { |
1579 | *here = data->to; |
1580 | *do_subtree = 0; |
1581 | } |
1582 | else |
1583 | *do_subtree = 1; |
1584 | return NULL_TREE(tree) nullptr; |
1585 | } |
1586 | |
1587 | /* Support for expansion of co_await statements. */ |
1588 | |
1589 | struct coro_aw_data |
1590 | { |
1591 | tree actor_fn; /* Decl for context. */ |
1592 | tree coro_fp; /* Frame pointer var. */ |
1593 | tree resume_idx; /* This is the index var in the frame. */ |
1594 | tree i_a_r_c; /* initial suspend await_resume() was called if true. */ |
1595 | tree self_h; /* This is a handle to the current coro (frame var). */ |
1596 | tree cleanup; /* This is where to go once we complete local destroy. */ |
1597 | tree cororet; /* This is where to go if we suspend. */ |
1598 | tree corocont; /* This is where to go if we continue. */ |
1599 | tree conthand; /* This is the handle for a continuation. */ |
1600 | unsigned index; /* This is our current resume index. */ |
1601 | }; |
1602 | |
1603 | /* Lightweight search for the first await expression in tree-walk order. |
1604 | returns: |
1605 | The first await expression found in STMT. |
1606 | NULL_TREE if there are none. |
1607 | So can be used to determine if the statement needs to be processed for |
1608 | awaits. */ |
1609 | |
1610 | static tree |
1611 | co_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 | |
1642 | static tree * |
1643 | expand_one_await_expression (tree *stmt, tree *await_expr, void *d) |
1644 | { |
1645 | coro_aw_data *data = (coro_aw_data *) d; |
1646 | |
1647 | tree saved_statement = *stmt; |
1648 | tree saved_co_await = *await_expr; |
1649 | |
1650 | tree actor = data->actor_fn; |
1651 | location_t loc = EXPR_LOCATION (*stmt)((((*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 | |
1855 | static tree |
1856 | process_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 | |
1864 | static tree |
1865 | await_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 | |
1895 | struct suspend_point_info |
1896 | { |
1897 | /* coro frame field type. */ |
1898 | tree awaitable_type; |
1899 | /* coro frame field name. */ |
1900 | tree await_field_id; |
1901 | }; |
1902 | |
1903 | static hash_map<tree, suspend_point_info> *suspend_points; |
1904 | |
1905 | struct await_xform_data |
1906 | { |
1907 | tree actor_fn; /* Decl for context. */ |
1908 | tree actor_frame; |
1909 | }; |
1910 | |
1911 | /* When we built the await expressions, we didn't know the coro frame |
1912 | layout, therefore no idea where to find the promise or where to put |
1913 | the awaitables. Now we know these things, fill them in. */ |
1914 | |
1915 | static tree |
1916 | transform_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 | |
1960 | static tree |
1961 | transform_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 | |
1984 | struct param_info |
1985 | { |
1986 | tree field_id; /* The name of the copy in the coroutine frame. */ |
1987 | tree copy_var; /* The local var proxy for the frame copy. */ |
1988 | vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */ |
1989 | tree frame_type; /* The type used to represent this parm in the frame. */ |
1990 | tree orig_type; /* The original type of the parm (not as passed). */ |
1991 | tree guard_var; /* If we need a DTOR on exception, this bool guards it. */ |
1992 | tree fr_copy_dtor; /* If we need a DTOR on exception, this is it. */ |
1993 | bool by_ref; /* Was passed by reference. */ |
1994 | bool pt_ref; /* Was a pointer to object. */ |
1995 | bool rv_ref; /* Was an rvalue ref. */ |
1996 | bool trivial_dtor; /* The frame type has a trivial DTOR. */ |
1997 | bool this_ptr; /* Is 'this' */ |
1998 | bool lambda_cobj; /* Lambda capture object */ |
1999 | }; |
2000 | |
2001 | struct local_var_info |
2002 | { |
2003 | tree field_id; |
2004 | tree field_idx; |
2005 | tree frame_type; |
2006 | bool is_lambda_capture; |
2007 | bool is_static; |
2008 | bool has_value_expr_p; |
2009 | location_t def_loc; |
2010 | }; |
2011 | |
2012 | /* For figuring out what local variable usage we have. */ |
2013 | struct local_vars_transform |
2014 | { |
2015 | tree context; |
2016 | tree actor_frame; |
2017 | tree coro_frame_type; |
2018 | location_t loc; |
2019 | hash_map<tree, local_var_info> *local_var_uses; |
2020 | }; |
2021 | |
2022 | static tree |
2023 | transform_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 | |
2086 | static tree |
2087 | coro_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 | |
2139 | static void |
2140 | build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, |
2141 | tree orig, hash_map<tree, local_var_info> *local_var_uses, |
2142 | vec<tree, va_gc> *param_dtor_list, |
2143 | tree resume_idx_var, unsigned body_count, tree frame_size) |
2144 | { |
2145 | 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 | |
2449 | static void |
2450 | build_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 | |
2494 | static tree |
2495 | get_fn_local_identifier (tree orig, const char *append) |
2496 | { |
2497 | /* Figure out the bits we need to generate names for the outlined things |
2498 | For consistency, this needs to behave the same way as |
2499 | ASM_FORMAT_PRIVATE_NAME does. */ |
2500 | 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 | |
2538 | static tree |
2539 | build_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 | |
2562 | static bool |
2563 | register_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 | |
2581 | struct susp_frame_data |
2582 | { |
2583 | /* Function-wide. */ |
2584 | tree *field_list; /* The current coroutine frame field list. */ |
2585 | tree handle_type; /* The self-handle type for this coroutine. */ |
2586 | tree fs_label; /* The destination for co_returns. */ |
2587 | vec<tree, va_gc> *block_stack; /* Track block scopes. */ |
2588 | vec<tree, va_gc> *bind_stack; /* Track current bind expr. */ |
2589 | unsigned await_number; /* Which await in the function. */ |
2590 | unsigned cond_number; /* Which replaced condition in the fn. */ |
2591 | /* Temporary values for one statement or expression being analyzed. */ |
2592 | hash_set<tree> captured_temps; /* The suspend captured these temps. */ |
2593 | vec<tree, va_gc> *to_replace; /* The VAR decls to replace. */ |
2594 | hash_set<tree> *truth_aoif_to_expand; /* The set of TRUTH exprs to expand. */ |
2595 | unsigned saw_awaits; /* Count of awaits in this statement */ |
2596 | bool captures_temporary; /* This expr captures temps by ref. */ |
2597 | bool needs_truth_if_exp; /* We must expand a truth_if expression. */ |
2598 | bool has_awaiter_init; /* We must handle initializing an awaiter. */ |
2599 | }; |
2600 | |
2601 | /* If this is an await expression, then count it (both uniquely within the |
2602 | function and locally within a single statement). */ |
2603 | |
2604 | static tree |
2605 | register_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. */ |
2642 | static tree |
2643 | find_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 | |
2655 | static bool |
2656 | tmp_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 | |
2671 | struct coro_interesting_subtree |
2672 | { |
2673 | tree* entry; |
2674 | hash_set<tree> *temps_used; |
2675 | }; |
2676 | |
2677 | /* tree-walk callback that returns the first encountered sub-expression of |
2678 | a kind that needs to be handled specifically by the statement flattener. */ |
2679 | |
2680 | static tree |
2681 | find_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 | |
2710 | struct 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 | |
2733 | static void |
2734 | flatten_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 | |
2940 | static void |
2941 | handle_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 | |
3008 | static void |
3009 | process_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 | |
3086 | static tree |
3087 | maybe_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 | |
3214 | static tree |
3215 | analyze_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 | |
3272 | struct truth_if_transform { |
3273 | tree *orig_stmt; |
3274 | tree scratch_var; |
3275 | hash_set<tree> *truth_aoif_to_expand; |
3276 | }; |
3277 | |
3278 | static tree |
3279 | expand_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 | |
3326 | static tree |
3327 | add_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 | |
3343 | static void |
3344 | coro_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. */ |
3355 | static tree |
3356 | replace_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 | |
3401 | static tree |
3402 | await_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 | |
3765 | struct param_frame_data |
3766 | { |
3767 | tree *field_list; |
3768 | hash_map<tree, param_info> *param_uses; |
3769 | hash_set<tree *> *visited; |
3770 | location_t loc; |
3771 | bool param_seen; |
3772 | }; |
3773 | |
3774 | /* A tree walk callback that rewrites each parm use to the local variable |
3775 | that represents its copy in the frame. */ |
3776 | |
3777 | static tree |
3778 | rewrite_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 | |
3807 | static hash_map<tree, param_info> * |
3808 | analyze_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__); <->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 | |
3887 | static tree |
3888 | coro_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 | |
3900 | struct local_vars_frame_data |
3901 | { |
3902 | tree *field_list; |
3903 | hash_map<tree, local_var_info> *local_var_uses; |
3904 | unsigned int nest_depth, bind_indx; |
3905 | location_t loc; |
3906 | bool saw_capture; |
3907 | bool local_var_seen; |
3908 | }; |
3909 | |
3910 | /* A tree-walk callback that processes one bind expression noting local |
3911 | variables, and making a coroutine frame slot available for those that |
3912 | need it, so that they can be 'promoted' across suspension points. */ |
3913 | |
3914 | static tree |
3915 | register_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 | |
4013 | static tree |
4014 | coro_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__); <->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 | |
4075 | static tree |
4076 | coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, |
4077 | hash_map<tree, param_info> *param_uses, |
4078 | tree resume_fn_ptr_type, |
4079 | tree& resume_idx_var, tree& fs_label) |
4080 | { |
4081 | /* This will be our new outer scope. */ |
4082 | 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, ¶m_data, NULL)walk_tree_1 (&fnbody, rewrite_param_uses, ¶m_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 | |
4372 | bool |
4373 | morph_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 |