Line data Source code
1 : // rust-gcc.cc -- Rust frontend to gcc IR.
2 : // Copyright (C) 2011-2026 Free Software Foundation, Inc.
3 : // Contributed by Ian Lance Taylor, Google.
4 : // forked from gccgo
5 :
6 : // This file is part of GCC.
7 :
8 : // GCC is free software; you can redistribute it and/or modify it under
9 : // the terms of the GNU General Public License as published by the Free
10 : // Software Foundation; either version 3, or (at your option) any later
11 : // version.
12 :
13 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : // for more details.
17 :
18 : // You should have received a copy of the GNU General Public License
19 : // along with GCC; see the file COPYING3. If not see
20 : // <http://www.gnu.org/licenses/>.
21 :
22 : #include "rust-system.h"
23 :
24 : // This has to be included outside of extern "C", so we have to
25 : // include it here before tree.h includes it later.
26 : #include <gmp.h>
27 :
28 : #include "tree.h"
29 : #include "opts.h"
30 : #include "fold-const.h"
31 : #include "stringpool.h"
32 : #include "stor-layout.h"
33 : #include "util/optional.h"
34 : #include "varasm.h"
35 : #include "tree-iterator.h"
36 : #include "tm.h"
37 : #include "function.h"
38 : #include "cgraph.h"
39 : #include "convert.h"
40 : #include "gimple-expr.h"
41 : #include "gimplify.h"
42 : #include "langhooks.h"
43 : #include "toplev.h"
44 : #include "output.h"
45 : #include "realmpfr.h"
46 : #include "builtins.h"
47 : #include "print-tree.h"
48 : #include "attribs.h"
49 :
50 : #include "rust-location.h"
51 : #include "rust-linemap.h"
52 : #include "rust-backend.h"
53 : #include "rust-object-export.h"
54 : #include "rust-gcc.h"
55 :
56 : #include "backend/rust-tree.h"
57 : #include "backend/rust-builtins.h"
58 :
59 : // Get the tree of a variable for use as an expression. If this is a
60 : // zero-sized global, create an expression that refers to the decl but
61 : // has zero size.
62 : tree
63 87253 : Bvariable::get_tree (location_t location) const
64 : {
65 87253 : if (error_operand_p (this->t_))
66 0 : return error_mark_node;
67 :
68 87253 : TREE_USED (this->t_) = 1;
69 87253 : if (this->orig_type_ == NULL || TREE_TYPE (this->t_) == this->orig_type_)
70 : {
71 87248 : return this->t_;
72 : }
73 :
74 : // Return *(orig_type*)&decl. */
75 5 : tree t = build_fold_addr_expr_loc (location, this->t_);
76 5 : t = fold_build1_loc (location, NOP_EXPR,
77 5 : build_pointer_type (this->orig_type_), t);
78 5 : return build_fold_indirect_ref_loc (location, t);
79 : }
80 :
81 : Bvariable *
82 11766 : Bvariable::error_variable ()
83 : {
84 11766 : return new Bvariable (error_mark_node);
85 : }
86 :
87 : // Get the tree of a variable for use as an expression
88 : tree
89 0 : LocalVariable::get_tree (location_t location) const
90 : {
91 0 : if (error_operand_p (t))
92 0 : return error_mark_node;
93 :
94 0 : TREE_USED (t) = 1;
95 0 : return t;
96 : }
97 :
98 : LocalVariable
99 6 : LocalVariable::error_variable ()
100 : {
101 6 : return LocalVariable (error_mark_node);
102 : }
103 :
104 : // This file implements the interface between the Rust frontend proper
105 : // and the gcc IR. This implements specific instantiations of
106 : // abstract classes defined by the Rust frontend proper. The Rust
107 : // frontend proper class methods of these classes to generate the
108 : // backend representation.
109 :
110 : // A helper function to create a GCC identifier from a C++ string.
111 :
112 : namespace Backend {
113 :
114 : // Define the built-in functions that are exposed to GCCRust.
115 :
116 : void
117 5191 : init ()
118 : {
119 : /* We need to define the fetch_and_add functions, since we use them
120 : for ++ and --. */
121 : // tree t = this->integer_type (true, BITS_PER_UNIT)->get_tree ();
122 : // tree p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
123 : // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_1,
124 : // "__sync_fetch_and_add_1",
125 : // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
126 :
127 : // t = this->integer_type (true, BITS_PER_UNIT * 2)->get_tree ();
128 : // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
129 : // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2,
130 : // "__sync_fetch_and_add_2",
131 : // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
132 :
133 : // t = this->integer_type (true, BITS_PER_UNIT * 4)->get_tree ();
134 : // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
135 : // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_4,
136 : // "__sync_fetch_and_add_4",
137 : // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
138 :
139 : // t = this->integer_type (true, BITS_PER_UNIT * 8)->get_tree ();
140 : // p = build_pointer_type (build_qualified_type (t, TYPE_QUAL_VOLATILE));
141 : // this->define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_8,
142 : // "__sync_fetch_and_add_8",
143 : // NULL, build_function_type_list (t, p, t, NULL_TREE), 0);
144 :
145 : // // We use __builtin_expect for magic import functions.
146 : // this->define_builtin (BUILT_IN_EXPECT, "__builtin_expect", NULL,
147 : // build_function_type_list (long_integer_type_node,
148 : // long_integer_type_node,
149 : // long_integer_type_node,
150 : // NULL_TREE),
151 : // builtin_const);
152 :
153 : // // We use __builtin_memcmp for struct comparisons.
154 : // this->define_builtin (BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
155 : // build_function_type_list (integer_type_node,
156 : // const_ptr_type_node,
157 : // const_ptr_type_node,
158 : // size_type_node, NULL_TREE),
159 : // 0);
160 :
161 : // // We use __builtin_memmove for copying data.
162 : // this->define_builtin (BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
163 : // build_function_type_list (void_type_node, ptr_type_node,
164 : // const_ptr_type_node,
165 : // size_type_node, NULL_TREE),
166 : // 0);
167 :
168 : // // We use __builtin_memset for zeroing data.
169 : // this->define_builtin (BUILT_IN_MEMSET, "__builtin_memset", "memset",
170 : // build_function_type_list (void_type_node, ptr_type_node,
171 : // integer_type_node,
172 : // size_type_node, NULL_TREE),
173 : // 0);
174 :
175 : // // Used by runtime/internal/sys and math/bits.
176 : // this->define_builtin (BUILT_IN_CTZ, "__builtin_ctz", "ctz",
177 : // build_function_type_list (integer_type_node,
178 : // unsigned_type_node,
179 : // NULL_TREE),
180 : // builtin_const);
181 : // this->define_builtin (BUILT_IN_CTZLL, "__builtin_ctzll", "ctzll",
182 : // build_function_type_list (integer_type_node,
183 : // long_long_unsigned_type_node,
184 : // NULL_TREE),
185 : // builtin_const);
186 : // this->define_builtin (BUILT_IN_CLZ, "__builtin_clz", "clz",
187 : // build_function_type_list (integer_type_node,
188 : // unsigned_type_node,
189 : // NULL_TREE),
190 : // builtin_const);
191 : // this->define_builtin (BUILT_IN_CLZLL, "__builtin_clzll", "clzll",
192 : // build_function_type_list (integer_type_node,
193 : // long_long_unsigned_type_node,
194 : // NULL_TREE),
195 : // builtin_const);
196 : // this->define_builtin (BUILT_IN_POPCOUNT, "__builtin_popcount", "popcount",
197 : // build_function_type_list (integer_type_node,
198 : // unsigned_type_node,
199 : // NULL_TREE),
200 : // builtin_const);
201 : // this->define_builtin (BUILT_IN_POPCOUNTLL, "__builtin_popcountll",
202 : // "popcountll",
203 : // build_function_type_list (integer_type_node,
204 : // long_long_unsigned_type_node,
205 : // NULL_TREE),
206 : // builtin_const);
207 : // this->define_builtin (BUILT_IN_BSWAP16, "__builtin_bswap16", "bswap16",
208 : // build_function_type_list (uint16_type_node,
209 : // uint16_type_node, NULL_TREE),
210 : // builtin_const);
211 : // this->define_builtin (BUILT_IN_BSWAP32, "__builtin_bswap32", "bswap32",
212 : // build_function_type_list (uint32_type_node,
213 : // uint32_type_node, NULL_TREE),
214 : // builtin_const);
215 : // this->define_builtin (BUILT_IN_BSWAP64, "__builtin_bswap64", "bswap64",
216 : // build_function_type_list (uint64_type_node,
217 : // uint64_type_node, NULL_TREE),
218 : // builtin_const);
219 :
220 : // We provide some functions for the math library.
221 :
222 : // We use __builtin_return_address in the thunk we build for
223 : // functions which call recover, and for runtime.getcallerpc.
224 : // t = build_function_type_list (ptr_type_node, unsigned_type_node,
225 : // NULL_TREE); this->define_builtin (BUILT_IN_RETURN_ADDRESS,
226 : // "__builtin_return_address",
227 : // NULL, t, 0);
228 :
229 : // The runtime calls __builtin_dwarf_cfa for runtime.getcallersp.
230 : // t = build_function_type_list (ptr_type_node, NULL_TREE);
231 : // this->define_builtin (BUILT_IN_DWARF_CFA, "__builtin_dwarf_cfa", NULL, t,
232 : // 0);
233 :
234 : // The runtime calls __builtin_extract_return_addr when recording
235 : // the address to which a function returns.
236 : // this->define_builtin (
237 : // BUILT_IN_EXTRACT_RETURN_ADDR, "__builtin_extract_return_addr", NULL,
238 : // build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE), 0);
239 :
240 : // The compiler uses __builtin_trap for some exception handling
241 : // cases.
242 : // this->define_builtin (BUILT_IN_TRAP, "__builtin_trap", NULL,
243 : // build_function_type (void_type_node, void_list_node),
244 : // builtin_noreturn);
245 :
246 : // The runtime uses __builtin_prefetch.
247 : // this->define_builtin (BUILT_IN_PREFETCH, "__builtin_prefetch", NULL,
248 : // build_varargs_function_type_list (void_type_node,
249 : // const_ptr_type_node,
250 : // NULL_TREE),
251 : // builtin_novops);
252 :
253 : // The compiler uses __builtin_unreachable for cases that cannot
254 : // occur.
255 : // this->define_builtin (BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL,
256 : // build_function_type (void_type_node, void_list_node),
257 : // builtin_const | builtin_noreturn);
258 :
259 : // We provide some atomic functions.
260 : // t = build_function_type_list (uint32_type_node, ptr_type_node,
261 : // integer_type_node, NULL_TREE);
262 : // this->define_builtin (BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", NULL, t,
263 : // 0);
264 :
265 : // t = build_function_type_list (uint64_type_node, ptr_type_node,
266 : // integer_type_node, NULL_TREE);
267 : // this->define_builtin (BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", NULL, t,
268 : // 0);
269 :
270 : // t = build_function_type_list (void_type_node, ptr_type_node,
271 : // uint32_type_node,
272 : // integer_type_node, NULL_TREE);
273 : // this->define_builtin (BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", NULL, t,
274 : // 0);
275 :
276 : // t = build_function_type_list (void_type_node, ptr_type_node,
277 : // uint64_type_node,
278 : // integer_type_node, NULL_TREE);
279 : // this->define_builtin (BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", NULL, t,
280 : // 0);
281 :
282 : // t = build_function_type_list (uint32_type_node, ptr_type_node,
283 : // uint32_type_node, integer_type_node, NULL_TREE);
284 : // this->define_builtin (BUILT_IN_ATOMIC_EXCHANGE_4, "__atomic_exchange_4",
285 : // NULL,
286 : // t, 0);
287 :
288 : // t = build_function_type_list (uint64_type_node, ptr_type_node,
289 : // uint64_type_node, integer_type_node, NULL_TREE);
290 : // this->define_builtin (BUILT_IN_ATOMIC_EXCHANGE_8, "__atomic_exchange_8",
291 : // NULL,
292 : // t, 0);
293 :
294 : // t = build_function_type_list (boolean_type_node, ptr_type_node,
295 : // ptr_type_node,
296 : // uint32_type_node, boolean_type_node,
297 : // integer_type_node, integer_type_node,
298 : // NULL_TREE);
299 : // this->define_builtin (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4,
300 : // "__atomic_compare_exchange_4", NULL, t, 0);
301 :
302 : // t = build_function_type_list (boolean_type_node, ptr_type_node,
303 : // ptr_type_node,
304 : // uint64_type_node, boolean_type_node,
305 : // integer_type_node, integer_type_node,
306 : // NULL_TREE);
307 : // this->define_builtin (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8,
308 : // "__atomic_compare_exchange_8", NULL, t, 0);
309 :
310 : // t = build_function_type_list (uint32_type_node, ptr_type_node,
311 : // uint32_type_node, integer_type_node, NULL_TREE);
312 : // this->define_builtin (BUILT_IN_ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4",
313 : // NULL, t, 0);
314 :
315 : // t = build_function_type_list (uint64_type_node, ptr_type_node,
316 : // uint64_type_node, integer_type_node, NULL_TREE);
317 : // this->define_builtin (BUILT_IN_ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8",
318 : // NULL, t, 0);
319 :
320 : // t = build_function_type_list (unsigned_char_type_node, ptr_type_node,
321 : // unsigned_char_type_node, integer_type_node,
322 : // NULL_TREE);
323 : // this->define_builtin (BUILT_IN_ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1",
324 : // NULL, t, 0);
325 : // this->define_builtin (BUILT_IN_ATOMIC_FETCH_AND_1, "__atomic_fetch_and_1",
326 : // NULL, t, 0);
327 :
328 : // t = build_function_type_list (unsigned_char_type_node, ptr_type_node,
329 : // unsigned_char_type_node, integer_type_node,
330 : // NULL_TREE);
331 : // this->define_builtin (BUILT_IN_ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1",
332 : // NULL,
333 : // t, 0);
334 : // this->define_builtin (BUILT_IN_ATOMIC_FETCH_OR_1, "__atomic_fetch_or_1",
335 : // NULL,
336 : // t, 0);
337 :
338 : // eagerly initialize BuiltinsContext
339 5191 : (void) Rust::Compile::BuiltinsContext::get ();
340 5191 : }
341 :
342 : void
343 0 : debug (tree t)
344 : {
345 0 : debug_tree (t);
346 0 : };
347 :
348 : void
349 0 : debug (Bvariable *t)
350 : {
351 0 : debug_tree (t->get_decl ());
352 0 : };
353 :
354 : tree
355 13086 : get_identifier_node (const std::string &str)
356 : {
357 13086 : return get_identifier_with_length (str.data (), str.length ());
358 : }
359 :
360 : tree
361 5941 : wchar_type ()
362 : {
363 5941 : static tree wchar;
364 :
365 5941 : if (wchar == NULL_TREE)
366 : {
367 4772 : wchar = make_unsigned_type (32);
368 4772 : TYPE_STRING_FLAG (wchar) = 1;
369 : }
370 :
371 5941 : return wchar;
372 : }
373 :
374 : // Get an unnamed integer type.
375 :
376 : int
377 58139 : get_pointer_size ()
378 : {
379 58139 : return POINTER_SIZE;
380 : }
381 :
382 : tree
383 0 : raw_str_type ()
384 : {
385 0 : tree char_ptr = build_pointer_type (char_type_node);
386 0 : tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
387 0 : return const_char_type;
388 : }
389 :
390 : tree
391 202004 : integer_type (bool is_unsigned, int bits)
392 : {
393 202004 : tree type;
394 202004 : if (is_unsigned)
395 : {
396 100532 : if (bits == INT_TYPE_SIZE)
397 14942 : type = unsigned_type_node;
398 85590 : else if (bits == SHORT_TYPE_SIZE)
399 9997 : type = short_unsigned_type_node;
400 75593 : else if (bits == LONG_TYPE_SIZE)
401 53683 : type = long_unsigned_type_node;
402 21910 : else if (bits == LONG_LONG_TYPE_SIZE)
403 0 : type = long_long_unsigned_type_node;
404 : else
405 21910 : type = make_unsigned_type (bits);
406 : }
407 : else
408 : {
409 101472 : if (bits == INT_TYPE_SIZE)
410 53536 : type = integer_type_node;
411 47936 : else if (bits == SHORT_TYPE_SIZE)
412 5959 : type = short_integer_type_node;
413 41977 : else if (bits == LONG_TYPE_SIZE)
414 25890 : type = long_integer_type_node;
415 16087 : else if (bits == LONG_LONG_TYPE_SIZE)
416 0 : type = long_long_integer_type_node;
417 : else
418 16087 : type = make_signed_type (bits);
419 : }
420 202004 : return type;
421 : }
422 :
423 : // Get an unnamed float type.
424 :
425 : tree
426 15784 : float_type (int bits)
427 : {
428 15784 : tree type;
429 15784 : if (bits == TYPE_PRECISION (float_type_node))
430 : type = float_type_node;
431 8125 : else if (bits == TYPE_PRECISION (double_type_node))
432 : type = double_type_node;
433 0 : else if (bits == TYPE_PRECISION (long_double_type_node))
434 : type = long_double_type_node;
435 : else
436 : {
437 0 : type = make_node (REAL_TYPE);
438 0 : TYPE_PRECISION (type) = bits;
439 0 : layout_type (type);
440 : }
441 15784 : return type;
442 : }
443 :
444 : // Get a pointer type.
445 :
446 : tree
447 8164 : pointer_type (tree to_type)
448 : {
449 8164 : if (error_operand_p (to_type))
450 0 : return error_mark_node;
451 8164 : tree type = build_pointer_type_for_mode (to_type, VOIDmode, true);
452 8164 : return type;
453 : }
454 :
455 : // Get a reference type.
456 :
457 : tree
458 14127 : reference_type (tree to_type)
459 : {
460 14127 : if (error_operand_p (to_type))
461 0 : return error_mark_node;
462 14127 : tree type = build_reference_type (to_type);
463 14127 : return type;
464 : }
465 :
466 : // Get immutable type
467 :
468 : tree
469 48567 : immutable_type (tree base)
470 : {
471 48567 : if (error_operand_p (base))
472 0 : return error_mark_node;
473 48567 : tree constified = build_qualified_type (base, TYPE_QUAL_CONST);
474 48567 : return constified;
475 : }
476 :
477 : // Make a function type.
478 :
479 : tree
480 20227 : function_type (const typed_identifier &receiver,
481 : const std::vector<typed_identifier> ¶meters,
482 : const std::vector<typed_identifier> &results, tree result_struct,
483 : location_t)
484 : {
485 20227 : tree args = NULL_TREE;
486 20227 : tree *pp = &args;
487 20227 : if (receiver.type != NULL_TREE)
488 : {
489 0 : tree t = receiver.type;
490 0 : if (error_operand_p (t))
491 0 : return error_mark_node;
492 0 : *pp = tree_cons (NULL_TREE, t, NULL_TREE);
493 0 : pp = &TREE_CHAIN (*pp);
494 : }
495 :
496 38819 : for (const auto &p : parameters)
497 : {
498 18592 : tree t = p.type;
499 18592 : if (error_operand_p (t))
500 0 : return error_mark_node;
501 18592 : *pp = tree_cons (NULL_TREE, t, NULL_TREE);
502 18592 : pp = &TREE_CHAIN (*pp);
503 : }
504 :
505 : // Varargs is handled entirely at the Rust level. When converted to
506 : // GENERIC functions are not varargs.
507 20227 : *pp = void_list_node;
508 :
509 20227 : tree result;
510 20227 : if (results.empty ())
511 246 : result = void_type_node;
512 19981 : else if (results.size () == 1)
513 19981 : result = results.front ().type;
514 : else
515 : {
516 0 : gcc_assert (result_struct != NULL);
517 : result = result_struct;
518 : }
519 20227 : if (error_operand_p (result))
520 0 : return error_mark_node;
521 :
522 20227 : tree fntype = build_function_type (result, args);
523 20227 : if (error_operand_p (fntype))
524 0 : return error_mark_node;
525 :
526 20227 : return build_pointer_type (fntype);
527 : }
528 :
529 : tree
530 883 : function_type_variadic (const typed_identifier &receiver,
531 : const std::vector<typed_identifier> ¶meters,
532 : const std::vector<typed_identifier> &results,
533 : tree result_struct, location_t)
534 : {
535 883 : size_t n = parameters.size () + (receiver.type != NULL_TREE ? 1 : 0);
536 883 : tree *args = XALLOCAVEC (tree, n);
537 883 : size_t offs = 0;
538 883 : if (error_operand_p (receiver.type))
539 0 : return error_mark_node;
540 :
541 883 : if (receiver.type != NULL_TREE)
542 0 : args[offs++] = receiver.type;
543 :
544 1766 : for (const auto &p : parameters)
545 : {
546 883 : tree t = p.type;
547 883 : if (error_operand_p (t))
548 0 : return error_mark_node;
549 883 : args[offs++] = t;
550 : }
551 :
552 883 : tree result;
553 883 : if (results.empty ())
554 855 : result = void_type_node;
555 28 : else if (results.size () == 1)
556 28 : result = results.front ().type;
557 : else
558 : {
559 0 : gcc_assert (result_struct != NULL_TREE);
560 : result = result_struct;
561 : }
562 883 : if (error_operand_p (result))
563 0 : return error_mark_node;
564 :
565 883 : tree fntype = build_varargs_function_type_array (result, n, args);
566 883 : if (error_operand_p (fntype))
567 0 : return error_mark_node;
568 :
569 883 : return build_pointer_type (fntype);
570 : }
571 :
572 : tree
573 112 : function_ptr_type (tree result_type, const std::vector<tree> ¶meters,
574 : location_t /* locus */)
575 : {
576 112 : tree args = NULL_TREE;
577 112 : tree *pp = &args;
578 :
579 204 : for (auto ¶m : parameters)
580 : {
581 92 : if (error_operand_p (param))
582 0 : return error_mark_node;
583 :
584 92 : *pp = tree_cons (NULL_TREE, param, NULL_TREE);
585 92 : pp = &TREE_CHAIN (*pp);
586 : }
587 :
588 112 : *pp = void_list_node;
589 :
590 112 : tree result = result_type;
591 112 : if (result != void_type_node && int_size_in_bytes (result) == 0)
592 64 : result = void_type_node;
593 :
594 112 : tree fntype = build_function_type (result, args);
595 112 : if (error_operand_p (fntype))
596 0 : return error_mark_node;
597 :
598 112 : return build_pointer_type (fntype);
599 : }
600 :
601 : // Make a struct type.
602 :
603 : tree
604 61259 : struct_type (const std::vector<typed_identifier> &fields, bool layout)
605 : {
606 61259 : return fill_in_fields (make_node (RECORD_TYPE), fields, layout);
607 : }
608 :
609 : // Make a union type.
610 :
611 : tree
612 7039 : union_type (const std::vector<typed_identifier> &fields, bool layout)
613 : {
614 7039 : return fill_in_fields (make_node (UNION_TYPE), fields, layout);
615 : }
616 :
617 : // Fill in the fields of a struct or union type.
618 :
619 : tree
620 68317 : fill_in_fields (tree fill, const std::vector<typed_identifier> &fields,
621 : bool layout)
622 : {
623 68317 : tree field_trees = NULL_TREE;
624 68317 : tree *pp = &field_trees;
625 168960 : for (const auto &p : fields)
626 : {
627 100646 : tree name_tree = p.name.as_tree ();
628 100646 : tree type_tree = p.type;
629 100646 : if (error_operand_p (type_tree))
630 3 : return error_mark_node;
631 100643 : tree field = build_decl (p.location, FIELD_DECL, name_tree, type_tree);
632 100643 : DECL_CONTEXT (field) = fill;
633 100643 : *pp = field;
634 100643 : pp = &DECL_CHAIN (field);
635 : }
636 68314 : TYPE_FIELDS (fill) = field_trees;
637 :
638 68314 : if (layout)
639 38964 : layout_type (fill);
640 :
641 : // Because Rust permits converting between named struct types and
642 : // equivalent struct types, for which we use VIEW_CONVERT_EXPR, and
643 : // because we don't try to maintain TYPE_CANONICAL for struct types,
644 : // we need to tell the middle-end to use structural equality.
645 68314 : SET_TYPE_STRUCTURAL_EQUALITY (fill);
646 :
647 68314 : return fill;
648 : }
649 :
650 : // Make an array type.
651 :
652 : tree
653 0 : array_type (tree element_type, tree length)
654 : {
655 0 : return fill_in_array (make_node (ARRAY_TYPE), element_type, length);
656 : }
657 :
658 : // Fill in an array type.
659 :
660 : tree
661 0 : fill_in_array (tree fill, tree element_type, tree length_tree)
662 : {
663 0 : if (error_operand_p (element_type) || error_operand_p (length_tree))
664 0 : return error_mark_node;
665 :
666 0 : gcc_assert (TYPE_SIZE (element_type) != NULL_TREE);
667 :
668 0 : length_tree = fold_convert (sizetype, length_tree);
669 :
670 : // build_index_type takes the maximum index, which is one less than
671 : // the length.
672 0 : tree index_type_tree = build_index_type (
673 : fold_build2 (MINUS_EXPR, sizetype, length_tree, size_one_node));
674 :
675 0 : TREE_TYPE (fill) = element_type;
676 0 : TYPE_DOMAIN (fill) = index_type_tree;
677 0 : TYPE_ADDR_SPACE (fill) = TYPE_ADDR_SPACE (element_type);
678 0 : layout_type (fill);
679 :
680 0 : if (TYPE_STRUCTURAL_EQUALITY_P (element_type))
681 0 : SET_TYPE_STRUCTURAL_EQUALITY (fill);
682 0 : else if (TYPE_CANONICAL (element_type) != element_type
683 0 : || TYPE_CANONICAL (index_type_tree) != index_type_tree)
684 0 : TYPE_CANONICAL (fill) = build_array_type (TYPE_CANONICAL (element_type),
685 0 : TYPE_CANONICAL (index_type_tree));
686 :
687 : return fill;
688 : }
689 :
690 : // Return a named version of a type.
691 :
692 : tree
693 302343 : named_type (GGC::Ident name, tree type, location_t location)
694 : {
695 302343 : if (error_operand_p (type))
696 3 : return error_mark_node;
697 :
698 : // The middle-end expects a basic type to have a name. In Rust every
699 : // basic type will have a name. The first time we see a basic type,
700 : // give it whatever Rust name we have at this point.
701 455617 : if (TYPE_NAME (type) == NULL_TREE && location == BUILTINS_LOCATION
702 399694 : && (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == REAL_TYPE
703 : || TREE_CODE (type) == COMPLEX_TYPE
704 : || TREE_CODE (type) == BOOLEAN_TYPE))
705 : {
706 85717 : tree decl
707 85717 : = build_decl (BUILTINS_LOCATION, TYPE_DECL, name.as_tree (), type);
708 85717 : TYPE_NAME (type) = decl;
709 85717 : return type;
710 : }
711 :
712 216623 : tree copy = build_variant_type_copy (type);
713 216623 : tree decl = build_decl (location, TYPE_DECL, name.as_tree (), copy);
714 216623 : DECL_ORIGINAL_TYPE (decl) = type;
715 216623 : TYPE_NAME (copy) = decl;
716 216623 : return copy;
717 : }
718 :
719 : // Return the size of a type.
720 :
721 : int64_t
722 40504 : type_size (tree t)
723 : {
724 40504 : if (error_operand_p (t))
725 : return 1;
726 40504 : if (t == void_type_node)
727 : return 0;
728 40504 : t = TYPE_SIZE_UNIT (t);
729 40504 : gcc_assert (tree_fits_uhwi_p (t));
730 40504 : unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW (t);
731 40504 : int64_t ret = static_cast<int64_t> (val_wide);
732 40504 : if (ret < 0 || static_cast<unsigned HOST_WIDE_INT> (ret) != val_wide)
733 : return -1;
734 : return ret;
735 : }
736 :
737 : // Return the alignment of a type.
738 :
739 : int64_t
740 0 : type_alignment (tree t)
741 : {
742 0 : if (error_operand_p (t))
743 : return 1;
744 0 : return TYPE_ALIGN_UNIT (t);
745 : }
746 :
747 : // Return the alignment of a struct field of type BTYPE.
748 :
749 : int64_t
750 0 : type_field_alignment (tree t)
751 : {
752 0 : if (error_operand_p (t))
753 : return 1;
754 0 : return rust_field_alignment (t);
755 : }
756 :
757 : // Return the offset of a field in a struct.
758 :
759 : int64_t
760 0 : type_field_offset (tree struct_tree, size_t index)
761 : {
762 0 : if (error_operand_p (struct_tree))
763 : return 0;
764 0 : gcc_assert (TREE_CODE (struct_tree) == RECORD_TYPE);
765 0 : tree field = TYPE_FIELDS (struct_tree);
766 0 : for (; index > 0; --index)
767 : {
768 0 : field = DECL_CHAIN (field);
769 0 : gcc_assert (field != NULL_TREE);
770 : }
771 0 : HOST_WIDE_INT offset_wide = int_byte_position (field);
772 0 : int64_t ret = static_cast<int64_t> (offset_wide);
773 0 : gcc_assert (ret == offset_wide);
774 0 : return ret;
775 : }
776 :
777 : // Return the zero value for a type.
778 :
779 : tree
780 105 : zero_expression (tree t)
781 : {
782 105 : tree ret;
783 105 : if (error_operand_p (t))
784 0 : ret = error_mark_node;
785 : else
786 105 : ret = build_zero_cst (t);
787 105 : return ret;
788 : }
789 :
790 : // An expression that references a variable.
791 :
792 : tree
793 77056 : var_expression (Bvariable *var, location_t location)
794 : {
795 77056 : return var->get_tree (location);
796 : }
797 :
798 : // Return a typed value as a constant floating-point number.
799 :
800 : tree
801 0 : float_constant_expression (tree t, mpfr_t val)
802 : {
803 0 : tree ret;
804 0 : if (error_operand_p (t))
805 0 : return error_mark_node;
806 :
807 0 : REAL_VALUE_TYPE r1;
808 0 : real_from_mpfr (&r1, val, t, GMP_RNDN);
809 0 : REAL_VALUE_TYPE r2;
810 0 : real_convert (&r2, TYPE_MODE (t), &r1);
811 0 : ret = build_real (t, r2);
812 0 : return ret;
813 : }
814 :
815 : // Make a constant string expression.
816 :
817 : tree
818 2421 : string_constant_expression (const std::string &val)
819 : {
820 2421 : tree index_type = build_index_type (size_int (val.length ()));
821 2421 : tree const_char_type = build_qualified_type (char_type_node, TYPE_QUAL_CONST);
822 2421 : tree string_type = build_array_type (const_char_type, index_type);
823 2421 : TYPE_STRING_FLAG (string_type) = 1;
824 2421 : tree string_val = build_string (val.length (), val.data ());
825 2421 : TREE_TYPE (string_val) = string_type;
826 :
827 2421 : return string_val;
828 : }
829 :
830 : tree
831 183 : wchar_constant_expression (wchar_t c)
832 : {
833 183 : return build_int_cst (wchar_type (), c);
834 : }
835 :
836 : tree
837 238 : char_constant_expression (char c)
838 : {
839 238 : return build_int_cst (char_type_node, c);
840 : }
841 :
842 : tree
843 340 : size_constant_expression (size_t val)
844 : {
845 340 : return size_int (val);
846 : }
847 :
848 : // Make a constant boolean expression.
849 :
850 : tree
851 4166 : boolean_constant_expression (bool val)
852 : {
853 4166 : return val ? boolean_true_node : boolean_false_node;
854 : }
855 :
856 : // An expression that converts an expression to a different type.
857 :
858 : tree
859 26 : convert_expression (tree type_tree, tree expr_tree, location_t location)
860 : {
861 26 : if (error_operand_p (type_tree) || error_operand_p (expr_tree))
862 0 : return error_mark_node;
863 :
864 26 : tree ret;
865 26 : if (type_size (type_tree) == 0 || TREE_TYPE (expr_tree) == void_type_node)
866 : {
867 : // Do not convert zero-sized types.
868 : ret = expr_tree;
869 : }
870 26 : else if (TREE_CODE (type_tree) == INTEGER_TYPE)
871 21 : ret = convert_to_integer (type_tree, expr_tree);
872 5 : else if (TREE_CODE (type_tree) == REAL_TYPE)
873 0 : ret = convert_to_real (type_tree, expr_tree);
874 5 : else if (TREE_CODE (type_tree) == COMPLEX_TYPE)
875 0 : ret = convert_to_complex (type_tree, expr_tree);
876 5 : else if (TREE_CODE (type_tree) == POINTER_TYPE
877 5 : && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
878 0 : ret = convert_to_pointer (type_tree, expr_tree);
879 5 : else if (TREE_CODE (type_tree) == RECORD_TYPE
880 5 : || TREE_CODE (type_tree) == ARRAY_TYPE)
881 0 : ret = fold_build1_loc (location, VIEW_CONVERT_EXPR, type_tree, expr_tree);
882 : else
883 5 : ret = fold_convert_loc (location, type_tree, expr_tree);
884 :
885 : return ret;
886 : }
887 :
888 : // Return an expression for the field at INDEX in BSTRUCT.
889 :
890 : tree
891 18557 : struct_field_expression (tree struct_tree, size_t index, location_t location)
892 : {
893 18557 : if (error_operand_p (struct_tree))
894 0 : return error_mark_node;
895 :
896 18557 : if (VECTOR_TYPE_P (TREE_TYPE (struct_tree)))
897 : {
898 3 : tree vec_type = TREE_TYPE (struct_tree);
899 3 : tree element_type = TREE_TYPE (vec_type);
900 3 : tree part_width = TYPE_SIZE (element_type);
901 3 : tree bit_offset = bitsize_int (index * tree_to_uhwi (part_width));
902 :
903 3 : return fold_build3_loc (location, BIT_FIELD_REF, element_type,
904 3 : struct_tree, part_width, bit_offset);
905 : }
906 :
907 18554 : gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE
908 : || TREE_CODE (TREE_TYPE (struct_tree)) == UNION_TYPE);
909 18554 : tree field = TYPE_FIELDS (TREE_TYPE (struct_tree));
910 18554 : if (field == NULL_TREE)
911 : {
912 : // This can happen for a type which refers to itself indirectly
913 : // and then turns out to be erroneous.
914 0 : return error_mark_node;
915 : }
916 42964 : for (unsigned int i = index; i > 0; --i)
917 : {
918 24410 : field = DECL_CHAIN (field);
919 24410 : gcc_assert (field != NULL_TREE);
920 : }
921 18554 : if (error_operand_p (TREE_TYPE (field)))
922 0 : return error_mark_node;
923 18554 : tree ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (field),
924 : struct_tree, field, NULL_TREE);
925 18554 : if (TREE_CONSTANT (struct_tree))
926 520 : TREE_CONSTANT (ret) = 1;
927 : return ret;
928 : }
929 :
930 : // Return an expression that executes BSTAT before BEXPR.
931 :
932 : tree
933 105 : compound_expression (tree stat, tree expr, location_t location)
934 : {
935 105 : if (error_operand_p (stat) || error_operand_p (expr))
936 0 : return error_mark_node;
937 105 : tree ret
938 105 : = fold_build2_loc (location, COMPOUND_EXPR, TREE_TYPE (expr), stat, expr);
939 105 : return ret;
940 : }
941 :
942 : // Return an expression that executes THEN_EXPR if CONDITION is true, or
943 : // ELSE_EXPR otherwise.
944 :
945 : tree
946 0 : conditional_expression (tree, tree type_tree, tree cond_expr, tree then_expr,
947 : tree else_expr, location_t location)
948 : {
949 0 : if (error_operand_p (type_tree) || error_operand_p (cond_expr)
950 0 : || error_operand_p (then_expr) || error_operand_p (else_expr))
951 0 : return error_mark_node;
952 0 : tree ret = build3_loc (location, COND_EXPR, type_tree, cond_expr, then_expr,
953 : else_expr);
954 0 : return ret;
955 : }
956 :
957 : /* Helper function that converts rust operators to equivalent GCC tree_code.
958 : Note that CompoundAssignmentOperator don't get their corresponding tree_code,
959 : because they get compiled away when we lower AST to HIR. */
960 : static enum tree_code
961 210 : operator_to_tree_code (NegationOperator op)
962 : {
963 210 : switch (op)
964 : {
965 : case NegationOperator::NEGATE:
966 : return NEGATE_EXPR;
967 187 : case NegationOperator::NOT:
968 187 : return BIT_NOT_EXPR;
969 0 : default:
970 0 : rust_unreachable ();
971 : }
972 : }
973 :
974 : /* Note that GCC tree code distinguishes floating point division and integer
975 : division. These two types of division are represented as the same rust
976 : operator, and can only be distinguished via context(i.e. the TREE_TYPE of the
977 : operands). */
978 : static enum tree_code
979 3052 : operator_to_tree_code (ArithmeticOrLogicalOperator op, bool floating_point)
980 : {
981 3052 : switch (op)
982 : {
983 : case ArithmeticOrLogicalOperator::ADD:
984 : return PLUS_EXPR;
985 118 : case ArithmeticOrLogicalOperator::SUBTRACT:
986 118 : return MINUS_EXPR;
987 117 : case ArithmeticOrLogicalOperator::MULTIPLY:
988 117 : return MULT_EXPR;
989 46 : case ArithmeticOrLogicalOperator::DIVIDE:
990 46 : if (floating_point)
991 : return RDIV_EXPR;
992 : else
993 37 : return TRUNC_DIV_EXPR;
994 56 : case ArithmeticOrLogicalOperator::MODULUS:
995 56 : return TRUNC_MOD_EXPR;
996 1659 : case ArithmeticOrLogicalOperator::BITWISE_AND:
997 1659 : return BIT_AND_EXPR;
998 132 : case ArithmeticOrLogicalOperator::BITWISE_OR:
999 132 : return BIT_IOR_EXPR;
1000 469 : case ArithmeticOrLogicalOperator::BITWISE_XOR:
1001 469 : return BIT_XOR_EXPR;
1002 71 : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
1003 71 : return LSHIFT_EXPR;
1004 26 : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
1005 26 : return RSHIFT_EXPR;
1006 0 : default:
1007 0 : rust_unreachable ();
1008 : }
1009 : }
1010 :
1011 : static enum tree_code
1012 5265 : operator_to_tree_code (ComparisonOperator op)
1013 : {
1014 5265 : switch (op)
1015 : {
1016 : case ComparisonOperator::EQUAL:
1017 : return EQ_EXPR;
1018 : case ComparisonOperator::NOT_EQUAL:
1019 : return NE_EXPR;
1020 : case ComparisonOperator::GREATER_THAN:
1021 : return GT_EXPR;
1022 : case ComparisonOperator::LESS_THAN:
1023 : return LT_EXPR;
1024 : case ComparisonOperator::GREATER_OR_EQUAL:
1025 : return GE_EXPR;
1026 : case ComparisonOperator::LESS_OR_EQUAL:
1027 : return LE_EXPR;
1028 0 : default:
1029 0 : rust_unreachable ();
1030 : }
1031 : }
1032 :
1033 : static enum tree_code
1034 473 : operator_to_tree_code (LazyBooleanOperator op)
1035 : {
1036 473 : switch (op)
1037 : {
1038 : case LazyBooleanOperator::LOGICAL_OR:
1039 : return TRUTH_ORIF_EXPR;
1040 339 : case LazyBooleanOperator::LOGICAL_AND:
1041 339 : return TRUTH_ANDIF_EXPR;
1042 0 : default:
1043 0 : rust_unreachable ();
1044 : }
1045 : }
1046 :
1047 : /* Returns true if the type of EXP is a floating point type.
1048 : False otherwise. */
1049 : bool
1050 7385 : is_floating_point (tree exp)
1051 : {
1052 7385 : return FLOAT_TYPE_P (TREE_TYPE (exp));
1053 : }
1054 :
1055 : // Return an expression for the negation operation OP EXPR.
1056 : tree
1057 210 : negation_expression (NegationOperator op, tree expr_tree, location_t location)
1058 : {
1059 : /* Check if the expression is an error, in which case we return an error
1060 : expression. */
1061 210 : if (error_operand_p (expr_tree))
1062 0 : return error_mark_node;
1063 :
1064 : /* For negation operators, the resulting type should be the same as its
1065 : operand. */
1066 210 : auto tree_type = TREE_TYPE (expr_tree);
1067 210 : auto original_type = tree_type;
1068 210 : auto tree_code = operator_to_tree_code (op);
1069 :
1070 : /* For floating point operations we may need to extend the precision of type.
1071 : For example, a 64-bit machine may not support operations on float32. */
1072 210 : bool floating_point = is_floating_point (expr_tree);
1073 210 : auto extended_type = NULL_TREE;
1074 210 : if (floating_point)
1075 : {
1076 0 : extended_type = excess_precision_type (tree_type);
1077 0 : if (extended_type != NULL_TREE)
1078 : {
1079 0 : expr_tree = convert (extended_type, expr_tree);
1080 0 : tree_type = extended_type;
1081 : }
1082 : }
1083 :
1084 : /* Construct a new tree and build an expression from it. */
1085 210 : auto new_tree = fold_build1_loc (location, tree_code, tree_type, expr_tree);
1086 210 : if (floating_point && extended_type != NULL_TREE)
1087 0 : new_tree = convert (original_type, expr_tree);
1088 : return new_tree;
1089 : }
1090 :
1091 : static tree
1092 3 : builtin_remainder_float_call (tree lhs, tree rhs, location_t loc)
1093 : {
1094 3 : auto builtin_ctx = Rust::Compile::BuiltinsContext::get ();
1095 3 : tl::optional<tree> remainder = tl::nullopt;
1096 :
1097 3 : if (TYPE_PRECISION (TREE_TYPE (lhs)) == TYPE_PRECISION (float_type_node))
1098 2 : remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainderf");
1099 1 : else if (TYPE_PRECISION (TREE_TYPE (lhs))
1100 1 : == TYPE_PRECISION (double_type_node))
1101 1 : remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainder");
1102 : // For f128, we will need to do the following - but gccrs doesn't handle f128
1103 : // at the moment AFAIK
1104 0 : else if (TYPE_PRECISION (TREE_TYPE (lhs))
1105 0 : == TYPE_PRECISION (long_double_type_node))
1106 0 : remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainderl");
1107 : else
1108 0 : rust_unreachable ();
1109 :
1110 3 : rust_assert (remainder);
1111 :
1112 3 : return build_call_expr_loc (loc, *remainder, 2, lhs, rhs);
1113 3 : }
1114 :
1115 : /**
1116 : * For floating point operations we may need to extend the precision of the
1117 : * type. For example, a 64-bit machine may not support operations on f32s.
1118 : *
1119 : * Returns NULL_TREE if there was no need to extend the type and the extended
1120 : * type otherwise.
1121 : */
1122 : static tree
1123 3052 : maybe_extend_precision (bool floating_point, tree &lhs, tree &rhs, tree &ty)
1124 : {
1125 3052 : auto extended_type = NULL_TREE;
1126 3052 : if (floating_point)
1127 : {
1128 243 : extended_type = excess_precision_type (ty);
1129 243 : if (extended_type != NULL_TREE)
1130 : {
1131 0 : lhs = convert (extended_type, lhs);
1132 0 : rhs = convert (extended_type, rhs);
1133 0 : ty = extended_type;
1134 : }
1135 : }
1136 :
1137 3052 : return extended_type;
1138 : }
1139 :
1140 : tree
1141 3053 : arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left,
1142 : tree right, location_t location)
1143 : {
1144 : /* Check if either expression is an error, in which case we return an error
1145 : expression. */
1146 3053 : if (error_operand_p (left) || error_operand_p (right))
1147 1 : return error_mark_node;
1148 :
1149 : // unwrap the const decls if set
1150 3052 : if (TREE_CODE (left) == CONST_DECL)
1151 144 : left = DECL_INITIAL (left);
1152 3052 : if (TREE_CODE (right) == CONST_DECL)
1153 31 : right = DECL_INITIAL (right);
1154 :
1155 : /* We need to determine if we're doing floating point arithmetics of integer
1156 : arithmetics. */
1157 3052 : bool floating_point = is_floating_point (left);
1158 3052 : auto ret = NULL_TREE;
1159 :
1160 : /* For arithmetic or logical operators, the resulting type should be the same
1161 : as the lhs operand. */
1162 3052 : auto tree_type = TREE_TYPE (left);
1163 3052 : auto original_type = tree_type;
1164 3052 : auto extended_type
1165 3052 : = maybe_extend_precision (floating_point, left, right, tree_type);
1166 :
1167 3052 : auto tree_code = operator_to_tree_code (op, floating_point);
1168 :
1169 : /* In the case of a floating point remainder operation, we have to perform a
1170 : * call to a builtin function instead as the mod operation is not supported on
1171 : * floating point values. But for all other operations, this is simply a
1172 : * build2 */
1173 3052 : if (floating_point && op == ArithmeticOrLogicalOperator::MODULUS)
1174 3 : ret = builtin_remainder_float_call (left, right, location);
1175 : else
1176 3049 : ret = build2_loc (location, tree_code, tree_type, left, right);
1177 :
1178 3052 : TREE_CONSTANT (ret) = TREE_CONSTANT (left) & TREE_CONSTANT (right);
1179 :
1180 : // TODO: How do we handle floating point?
1181 3052 : if (floating_point && extended_type != NULL_TREE)
1182 0 : ret = convert (original_type, ret);
1183 :
1184 3052 : if (op == ArithmeticOrLogicalOperator::DIVIDE
1185 3052 : && (integer_zerop (right) || fixed_zerop (right)))
1186 : {
1187 4 : rust_error_at (location, "division by zero");
1188 : }
1189 3048 : else if (op == ArithmeticOrLogicalOperator::LEFT_SHIFT
1190 71 : && TREE_CODE (right) == INTEGER_CST
1191 3089 : && (compare_tree_int (right, TYPE_PRECISION (TREE_TYPE (ret))) >= 0))
1192 : {
1193 1 : rust_error_at (location, "left shift count >= width of type");
1194 : }
1195 :
1196 : return ret;
1197 : }
1198 :
1199 : static bool
1200 3900 : is_overflowing_expr (ArithmeticOrLogicalOperator op)
1201 : {
1202 3900 : switch (op)
1203 : {
1204 : case ArithmeticOrLogicalOperator::ADD:
1205 : case ArithmeticOrLogicalOperator::SUBTRACT:
1206 : case ArithmeticOrLogicalOperator::MULTIPLY:
1207 : return true;
1208 0 : default:
1209 0 : return false;
1210 : }
1211 : }
1212 :
1213 : static std::pair<tree, tree>
1214 3095 : fetch_overflow_builtins (ArithmeticOrLogicalOperator op)
1215 : {
1216 3095 : auto builtin_ctx = Rust::Compile::BuiltinsContext::get ();
1217 :
1218 3095 : tl::optional<tree> builtin = NULL_TREE;
1219 :
1220 3095 : switch (op)
1221 : {
1222 1794 : case ArithmeticOrLogicalOperator::ADD:
1223 1794 : builtin = builtin_ctx.lookup_simple_builtin ("__builtin_add_overflow");
1224 1794 : break;
1225 1125 : case ArithmeticOrLogicalOperator::SUBTRACT:
1226 1125 : builtin = builtin_ctx.lookup_simple_builtin ("__builtin_sub_overflow");
1227 1125 : break;
1228 176 : case ArithmeticOrLogicalOperator::MULTIPLY:
1229 176 : builtin = builtin_ctx.lookup_simple_builtin ("__builtin_mul_overflow");
1230 176 : break;
1231 0 : default:
1232 0 : rust_unreachable ();
1233 3095 : break;
1234 3095 : };
1235 :
1236 3095 : auto abort = builtin_ctx.lookup_simple_builtin ("__builtin_abort");
1237 :
1238 3095 : rust_assert (abort);
1239 3095 : rust_assert (builtin);
1240 :
1241 3095 : return {*abort, *builtin};
1242 3095 : }
1243 :
1244 : // Return an expression for the arithmetic or logical operation LEFT OP RIGHT
1245 : // with overflow checking when possible
1246 : tree
1247 4123 : arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op,
1248 : tree left, tree right,
1249 : location_t location,
1250 : Bvariable *receiver_var)
1251 : {
1252 : /* Check if either expression is an error, in which case we return an error
1253 : expression. */
1254 4123 : if (error_operand_p (left) || error_operand_p (right))
1255 0 : return error_mark_node;
1256 :
1257 : // FIXME: Add `if (!debug_mode)`
1258 : // No overflow checks for floating point operations or divisions. In that
1259 : // case, simply assign the result of the operation to the receiver variable
1260 4123 : if (is_floating_point (left) || !is_overflowing_expr (op))
1261 1028 : return assignment_statement (
1262 : receiver_var->get_tree (location),
1263 1028 : arithmetic_or_logical_expression (op, left, right, location), location);
1264 :
1265 3095 : auto receiver = receiver_var->get_tree (location);
1266 3095 : TREE_ADDRESSABLE (receiver) = 1;
1267 3095 : auto result_ref = build_fold_addr_expr_loc (location, receiver);
1268 :
1269 3095 : auto builtins = fetch_overflow_builtins (op);
1270 3095 : auto abort = builtins.first;
1271 3095 : auto builtin = builtins.second;
1272 :
1273 3095 : auto abort_call = build_call_expr_loc (location, abort, 0);
1274 :
1275 3095 : auto builtin_call
1276 3095 : = build_call_expr_loc (location, builtin, 3, left, right, result_ref);
1277 3095 : auto overflow_check
1278 3095 : = build2_loc (location, EQ_EXPR, boolean_type_node, builtin_call,
1279 : boolean_constant_expression (true));
1280 :
1281 3095 : auto if_block = build3_loc (location, COND_EXPR, void_type_node,
1282 : overflow_check, abort_call, NULL_TREE);
1283 :
1284 3095 : return if_block;
1285 : }
1286 :
1287 : // Return an expression for the comparison operation LEFT OP RIGHT.
1288 : tree
1289 5266 : comparison_expression (ComparisonOperator op, tree left_tree, tree right_tree,
1290 : location_t location)
1291 : {
1292 : /* Check if either expression is an error, in which case we return an error
1293 : expression. */
1294 5266 : if (error_operand_p (left_tree) || error_operand_p (right_tree))
1295 1 : return error_mark_node;
1296 :
1297 : /* For comparison operators, the resulting type should be boolean. */
1298 5265 : auto tree_type = boolean_type_node;
1299 5265 : auto tree_code = operator_to_tree_code (op);
1300 :
1301 : /* Construct a new tree and build an expression from it. */
1302 5265 : auto new_tree
1303 5265 : = fold_build2_loc (location, tree_code, tree_type, left_tree, right_tree);
1304 5265 : return new_tree;
1305 : }
1306 :
1307 : // Return an expression for the lazy boolean operation LEFT OP RIGHT.
1308 : tree
1309 473 : lazy_boolean_expression (LazyBooleanOperator op, tree left_tree,
1310 : tree right_tree, location_t location)
1311 : {
1312 : /* Check if either expression is an error, in which case we return an error
1313 : expression. */
1314 473 : if (error_operand_p (left_tree) || error_operand_p (right_tree))
1315 0 : return error_mark_node;
1316 :
1317 : /* For lazy boolean operators, the resulting type should be the same as the
1318 : rhs operand. */
1319 473 : auto tree_type = TREE_TYPE (right_tree);
1320 473 : auto tree_code = operator_to_tree_code (op);
1321 :
1322 : /* Construct a new tree and build an expression from it. */
1323 473 : auto new_tree
1324 473 : = fold_build2_loc (location, tree_code, tree_type, left_tree, right_tree);
1325 473 : return new_tree;
1326 : }
1327 :
1328 : // Return an expression that constructs BTYPE with VALS.
1329 :
1330 : tree
1331 22040 : constructor_expression (tree type_tree, bool is_variant,
1332 : const std::vector<tree> &vals, int union_index,
1333 : location_t location)
1334 : {
1335 22040 : if (error_operand_p (type_tree))
1336 1 : return error_mark_node;
1337 :
1338 22039 : vec<constructor_elt, va_gc> *init;
1339 42976 : vec_alloc (init, union_index != -1 ? 1 : vals.size ());
1340 :
1341 22039 : if (VECTOR_TYPE_P (type_tree))
1342 : {
1343 2 : tree element_type = TREE_TYPE (type_tree);
1344 2 : bool is_constant = true;
1345 10 : for (size_t i = 0; i < vals.size (); ++i)
1346 : {
1347 8 : tree val = vals[i];
1348 8 : if (error_operand_p (val))
1349 0 : return error_mark_node;
1350 :
1351 8 : constructor_elt empty = {NULL, NULL};
1352 8 : constructor_elt *elt = init->quick_push (empty);
1353 8 : elt->index = size_int (i);
1354 8 : elt->value = convert_tree (element_type, val, location);
1355 :
1356 8 : if (!TREE_CONSTANT (elt->value))
1357 8 : is_constant = false;
1358 : }
1359 :
1360 2 : tree ret = build_constructor (type_tree, init);
1361 2 : if (is_constant)
1362 0 : TREE_CONSTANT (ret) = 1;
1363 :
1364 : return ret;
1365 : }
1366 :
1367 22037 : tree sink = NULL_TREE;
1368 22037 : bool is_constant = true;
1369 22037 : tree field = TYPE_FIELDS (type_tree);
1370 :
1371 22037 : if (is_variant)
1372 : {
1373 1002 : gcc_assert (union_index != -1);
1374 1002 : gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
1375 :
1376 1933 : for (int i = 0; i < union_index; i++)
1377 : {
1378 931 : gcc_assert (field != NULL_TREE);
1379 931 : field = DECL_CHAIN (field);
1380 : }
1381 :
1382 1002 : tree nested_ctor
1383 1002 : = constructor_expression (TREE_TYPE (field), false, vals, -1, location);
1384 :
1385 1002 : constructor_elt empty = {NULL, NULL};
1386 1002 : constructor_elt *elt = init->quick_push (empty);
1387 1002 : elt->index = field;
1388 1002 : elt->value = convert_tree (TREE_TYPE (field), nested_ctor, location);
1389 1002 : if (!TREE_CONSTANT (elt->value))
1390 291 : is_constant = false;
1391 : }
1392 : else
1393 : {
1394 21035 : if (union_index != -1)
1395 : {
1396 100 : gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
1397 100 : tree val = vals.front ();
1398 209 : for (int i = 0; i < union_index; i++)
1399 : {
1400 109 : gcc_assert (field != NULL_TREE);
1401 109 : field = DECL_CHAIN (field);
1402 : }
1403 :
1404 100 : if (TREE_TYPE (field) == error_mark_node || error_operand_p (val))
1405 : return error_mark_node;
1406 :
1407 100 : if (int_size_in_bytes (TREE_TYPE (field)) == 0)
1408 : {
1409 : // GIMPLE cannot represent indices of zero-sized types so
1410 : // trying to construct a map with zero-sized keys might lead
1411 : // to errors. Instead, we evaluate each expression that
1412 : // would have been added as a map element for its
1413 : // side-effects and construct an empty map.
1414 0 : append_to_statement_list (val, &sink);
1415 : }
1416 : else
1417 : {
1418 100 : constructor_elt empty = {NULL, NULL};
1419 100 : constructor_elt *elt = init->quick_push (empty);
1420 100 : elt->index = field;
1421 100 : elt->value = convert_tree (TREE_TYPE (field), val, location);
1422 100 : if (!TREE_CONSTANT (elt->value))
1423 61 : is_constant = false;
1424 : }
1425 : }
1426 : else
1427 : {
1428 20935 : gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
1429 20935 : for (std::vector<tree>::const_iterator p = vals.begin ();
1430 37253 : p != vals.end (); ++p, field = DECL_CHAIN (field))
1431 : {
1432 16318 : gcc_assert (field != NULL_TREE);
1433 16318 : tree val = (*p);
1434 16318 : if (TREE_TYPE (field) == error_mark_node || error_operand_p (val))
1435 0 : return error_mark_node;
1436 :
1437 16318 : if (int_size_in_bytes (TREE_TYPE (field)) == 0)
1438 : {
1439 : // GIMPLE cannot represent indices of zero-sized types so
1440 : // trying to construct a map with zero-sized keys might lead
1441 : // to errors. Instead, we evaluate each expression that
1442 : // would have been added as a map element for its
1443 : // side-effects and construct an empty map.
1444 99 : append_to_statement_list (val, &sink);
1445 99 : continue;
1446 : }
1447 :
1448 16219 : constructor_elt empty = {NULL, NULL};
1449 16219 : constructor_elt *elt = init->quick_push (empty);
1450 16219 : elt->index = field;
1451 16219 : elt->value = convert_tree (TREE_TYPE (field), val, location);
1452 16219 : if (!TREE_CONSTANT (elt->value))
1453 3320 : is_constant = false;
1454 : }
1455 : // gcc_assert (field == NULL_TREE);
1456 : }
1457 : }
1458 :
1459 22037 : tree ret = build_constructor (type_tree, init);
1460 22037 : if (is_constant)
1461 19725 : TREE_CONSTANT (ret) = 1;
1462 22037 : if (sink != NULL_TREE)
1463 2 : ret = fold_build2_loc (location, COMPOUND_EXPR, type_tree, sink, ret);
1464 : return ret;
1465 : }
1466 :
1467 : tree
1468 337 : array_constructor_expression (tree type_tree,
1469 : const std::vector<unsigned long> &indexes,
1470 : const std::vector<tree> &vals,
1471 : location_t location)
1472 : {
1473 337 : if (error_operand_p (type_tree))
1474 0 : return error_mark_node;
1475 :
1476 337 : gcc_assert (indexes.size () == vals.size ());
1477 :
1478 337 : tree element_type = TREE_TYPE (type_tree);
1479 337 : HOST_WIDE_INT element_size = int_size_in_bytes (element_type);
1480 337 : vec<constructor_elt, va_gc> *init;
1481 671 : vec_alloc (init, element_size == 0 ? 0 : vals.size ());
1482 :
1483 337 : tree sink = NULL_TREE;
1484 337 : bool is_constant = true;
1485 2232 : for (size_t i = 0; i < vals.size (); ++i)
1486 : {
1487 1895 : tree index = size_int (indexes[i]);
1488 1895 : tree val = vals[i];
1489 :
1490 1895 : if (error_operand_p (index) || error_operand_p (val))
1491 0 : return error_mark_node;
1492 :
1493 1895 : if (element_size == 0)
1494 : {
1495 : // GIMPLE cannot represent arrays of zero-sized types so trying
1496 : // to construct an array of zero-sized values might lead to errors.
1497 : // Instead, we evaluate each expression that would have been added as
1498 : // an array value for its side-effects and construct an empty array.
1499 4 : append_to_statement_list (val, &sink);
1500 4 : continue;
1501 : }
1502 :
1503 1891 : if (!TREE_CONSTANT (val))
1504 9 : is_constant = false;
1505 :
1506 1891 : constructor_elt empty = {NULL, NULL};
1507 1891 : constructor_elt *elt = init->quick_push (empty);
1508 1891 : elt->index = index;
1509 1891 : elt->value = val;
1510 : }
1511 :
1512 337 : tree ret = build_constructor (type_tree, init);
1513 337 : if (is_constant)
1514 328 : TREE_CONSTANT (ret) = 1;
1515 337 : if (sink != NULL_TREE)
1516 3 : ret = fold_build2_loc (location, COMPOUND_EXPR, type_tree, sink, ret);
1517 : return ret;
1518 : }
1519 :
1520 : // Build insns to create an array, initialize all elements of the array to
1521 : // value, and return it
1522 : tree
1523 105 : array_initializer (tree fndecl, tree block, tree array_type, tree length,
1524 : tree value, tree *tmp, location_t locus)
1525 : {
1526 105 : std::vector<tree> stmts;
1527 :
1528 : // Temporary array we initialize with the desired value.
1529 105 : tree t = NULL_TREE;
1530 105 : Bvariable *tmp_array = temporary_variable (fndecl, block, array_type,
1531 : NULL_TREE, true, locus, &t);
1532 105 : tree arr = tmp_array->get_tree (locus);
1533 105 : stmts.push_back (t);
1534 :
1535 : // Temporary for the array length used for initialization loop guard.
1536 105 : Bvariable *tmp_len = temporary_variable (fndecl, block, size_type_node,
1537 : length, true, locus, &t);
1538 105 : tree len = tmp_len->get_tree (locus);
1539 105 : stmts.push_back (t);
1540 :
1541 : // Temporary variable for pointer used to initialize elements.
1542 105 : tree ptr_type = pointer_type (TREE_TYPE (array_type));
1543 105 : tree ptr_init
1544 105 : = build1_loc (locus, ADDR_EXPR, ptr_type,
1545 : array_index_expression (arr, integer_zero_node, locus));
1546 105 : Bvariable *tmp_ptr
1547 105 : = temporary_variable (fndecl, block, ptr_type, ptr_init, false, locus, &t);
1548 105 : tree ptr = tmp_ptr->get_tree (locus);
1549 105 : stmts.push_back (t);
1550 :
1551 : // push statement list for the loop
1552 105 : std::vector<tree> loop_stmts;
1553 :
1554 : // Loop exit condition:
1555 : // if (length == 0) break;
1556 105 : t = comparison_expression (ComparisonOperator::EQUAL, len,
1557 105 : zero_expression (TREE_TYPE (len)), locus);
1558 :
1559 105 : t = exit_expression (t, locus);
1560 105 : loop_stmts.push_back (t);
1561 :
1562 : // Assign value to the current pointer position
1563 : // *ptr = value;
1564 105 : t = assignment_statement (build_fold_indirect_ref (ptr), value, locus);
1565 105 : loop_stmts.push_back (t);
1566 :
1567 : // Move pointer to next element
1568 : // ptr++;
1569 105 : tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptr_type));
1570 105 : t = build2 (POSTINCREMENT_EXPR, ptr_type, ptr, convert (ptr_type, size));
1571 105 : loop_stmts.push_back (t);
1572 :
1573 : // Decrement loop counter.
1574 : // length--;
1575 105 : t = build2 (POSTDECREMENT_EXPR, TREE_TYPE (len), len,
1576 105 : convert (TREE_TYPE (len), integer_one_node));
1577 105 : loop_stmts.push_back (t);
1578 :
1579 : // pop statments and finish loop
1580 105 : tree loop_body = statement_list (loop_stmts);
1581 105 : stmts.push_back (loop_expression (loop_body, locus));
1582 :
1583 : // Return the temporary in the provided pointer and the statement list which
1584 : // initializes it.
1585 105 : *tmp = tmp_array->get_tree (locus);
1586 105 : return statement_list (stmts);
1587 105 : }
1588 :
1589 : // Return an expression representing ARRAY[INDEX]
1590 :
1591 : tree
1592 476 : array_index_expression (tree array_tree, tree index_tree, location_t location)
1593 : {
1594 476 : if (error_operand_p (array_tree) || error_operand_p (index_tree))
1595 0 : return error_mark_node;
1596 :
1597 : // A function call that returns a zero sized object will have been
1598 : // changed to return void. If we see void here, assume we are
1599 : // dealing with a zero sized type and just evaluate the operands.
1600 476 : tree ret;
1601 476 : if (TREE_TYPE (array_tree) != void_type_node)
1602 476 : ret = build4_loc (location, ARRAY_REF, TREE_TYPE (TREE_TYPE (array_tree)),
1603 : array_tree, index_tree, NULL_TREE, NULL_TREE);
1604 : else
1605 0 : ret = fold_build2_loc (location, COMPOUND_EXPR, void_type_node, array_tree,
1606 : index_tree);
1607 :
1608 : return ret;
1609 : }
1610 :
1611 : // Return an expression representing SLICE[INDEX]
1612 :
1613 : tree
1614 150 : slice_index_expression (tree slice_tree, tree index_tree, location_t location)
1615 : {
1616 150 : if (error_operand_p (slice_tree) || error_operand_p (index_tree))
1617 0 : return error_mark_node;
1618 :
1619 : // A slice is created in TyTyResolvecompile::create_slice_type_record
1620 : // For example:
1621 : // &[i32] is turned directly into a struct { i32* data, usize len };
1622 : // [i32] is also turned into struct { i32* data, usize len }
1623 :
1624 : // it should have RS_DST_FLAG set to 1
1625 150 : rust_assert (RS_DST_FLAG_P (TREE_TYPE (slice_tree)));
1626 :
1627 150 : tree data_field = struct_field_expression (slice_tree, 0, location);
1628 150 : tree data_field_deref = build_fold_indirect_ref_loc (location, data_field);
1629 :
1630 150 : tree element_type = TREE_TYPE (data_field_deref);
1631 150 : tree data_pointer = TREE_OPERAND (data_field_deref, 0);
1632 150 : rust_assert (POINTER_TYPE_P (TREE_TYPE (data_pointer)));
1633 150 : tree data_offset_expr
1634 150 : = Rust::pointer_offset_expression (data_pointer, index_tree, location);
1635 :
1636 150 : return build1_loc (location, INDIRECT_REF, element_type, data_offset_expr);
1637 : }
1638 :
1639 : // Rust evaluates the callee and then the arguments of a call from left to
1640 : // right, but gimplify_call_expr evaluates the arguments in the order the
1641 : // target pushes them, which is right to left on x86. When anything in the
1642 : // call has side effects, wrap the callee and every argument but the last in
1643 : // a SAVE_EXPR, and return those in order so that the caller can evaluate
1644 : // them before the call. The call then only evaluates its last argument.
1645 :
1646 : static std::vector<tree>
1647 16717 : save_call_operands (tree &fn, tree *args, size_t nargs)
1648 : {
1649 16717 : std::vector<tree> saved;
1650 :
1651 16717 : bool has_side_effects = TREE_SIDE_EFFECTS (fn);
1652 38010 : for (size_t i = 0; i < nargs && !has_side_effects; ++i)
1653 21293 : has_side_effects = TREE_SIDE_EFFECTS (args[i]);
1654 :
1655 16717 : if (!has_side_effects || nargs == 0)
1656 : return saved;
1657 :
1658 185 : if (TREE_SIDE_EFFECTS (fn))
1659 : {
1660 0 : fn = save_expr (fn);
1661 0 : saved.push_back (fn);
1662 : }
1663 :
1664 377 : for (size_t i = 0; i + 1 < nargs; ++i)
1665 : {
1666 192 : if (VOID_TYPE_P (TREE_TYPE (args[i])) || really_constant_p (args[i]))
1667 21 : continue;
1668 :
1669 171 : args[i] = save_expr (args[i]);
1670 171 : if (TREE_CODE (args[i]) == SAVE_EXPR)
1671 171 : saved.push_back (args[i]);
1672 : }
1673 :
1674 : return saved;
1675 : }
1676 :
1677 : // Create an expression for a call to FN_EXPR with FN_ARGS.
1678 : tree
1679 16736 : call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr,
1680 : location_t location)
1681 : {
1682 16736 : if (error_operand_p (fn))
1683 19 : return error_mark_node;
1684 :
1685 16717 : gcc_assert (FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn)));
1686 16717 : tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn)));
1687 :
1688 16717 : size_t nargs = fn_args.size ();
1689 16717 : tree *args = nargs == 0 ? NULL : new tree[nargs];
1690 38108 : for (size_t i = 0; i < nargs; ++i)
1691 : {
1692 21391 : args[i] = fn_args.at (i);
1693 : }
1694 :
1695 16717 : tree fndecl = fn;
1696 16717 : if (TREE_CODE (fndecl) == ADDR_EXPR)
1697 16467 : fndecl = TREE_OPERAND (fndecl, 0);
1698 :
1699 : // This is to support builtin math functions when using 80387 math.
1700 16717 : tree excess_type = NULL_TREE;
1701 13411 : if (optimize && TREE_CODE (fndecl) == FUNCTION_DECL
1702 13209 : && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
1703 1830 : && DECL_IS_UNDECLARED_BUILTIN (fndecl) && nargs > 0
1704 17883 : && ((SCALAR_FLOAT_TYPE_P (rettype)
1705 252 : && SCALAR_FLOAT_TYPE_P (TREE_TYPE (args[0])))
1706 914 : || (COMPLEX_FLOAT_TYPE_P (rettype)
1707 0 : && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (args[0])))))
1708 : {
1709 252 : excess_type = excess_precision_type (TREE_TYPE (args[0]));
1710 252 : if (excess_type != NULL_TREE)
1711 : {
1712 0 : tree excess_fndecl
1713 0 : = mathfn_built_in (excess_type, DECL_FUNCTION_CODE (fndecl));
1714 0 : if (excess_fndecl == NULL_TREE)
1715 : excess_type = NULL_TREE;
1716 : else
1717 : {
1718 0 : fn = build_fold_addr_expr_loc (location, excess_fndecl);
1719 0 : for (size_t i = 0; i < nargs; ++i)
1720 : {
1721 0 : if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (args[i]))
1722 0 : || COMPLEX_FLOAT_TYPE_P (TREE_TYPE (args[i])))
1723 0 : args[i] = ::convert (excess_type, args[i]);
1724 : }
1725 : }
1726 : }
1727 : }
1728 :
1729 16717 : std::vector<tree> saved = save_call_operands (fn, args, nargs);
1730 :
1731 16717 : tree ret
1732 33434 : = build_call_array_loc (location,
1733 : excess_type != NULL_TREE ? excess_type : rettype,
1734 : fn, nargs, args);
1735 :
1736 : // check for deprecated function usage
1737 16717 : if (fndecl && TREE_DEPRECATED (fndecl))
1738 : {
1739 : // set up the call-site information for `warn_deprecated_use`
1740 5 : input_location = location;
1741 5 : warn_deprecated_use (fndecl, NULL_TREE);
1742 : }
1743 :
1744 16717 : if (chain_expr)
1745 0 : CALL_EXPR_STATIC_CHAIN (ret) = chain_expr;
1746 :
1747 16717 : if (excess_type != NULL_TREE)
1748 : {
1749 : // Calling convert here can undo our excess precision change.
1750 : // That may or may not be a bug in convert_to_real.
1751 0 : ret = build1_loc (location, NOP_EXPR, rettype, ret);
1752 : }
1753 :
1754 : // evaluate the saved operands in order before the call
1755 16888 : for (auto it = saved.rbegin (); it != saved.rend (); ++it)
1756 171 : ret = build2_loc (location, COMPOUND_EXPR, TREE_TYPE (ret), *it, ret);
1757 :
1758 16717 : delete[] args;
1759 16717 : return ret;
1760 16717 : }
1761 :
1762 : // Variable initialization.
1763 :
1764 : tree
1765 12007 : init_statement (tree, Bvariable *var, tree init_tree)
1766 : {
1767 12007 : tree var_tree = var->get_decl ();
1768 12007 : if (error_operand_p (var_tree) || error_operand_p (init_tree))
1769 3 : return error_mark_node;
1770 12004 : gcc_assert (TREE_CODE (var_tree) == VAR_DECL);
1771 :
1772 : // To avoid problems with GNU ld, we don't make zero-sized
1773 : // externally visible variables. That might lead us to doing an
1774 : // initialization of a zero-sized expression to a non-zero sized
1775 : // variable, or vice-versa. Avoid crashes by omitting the
1776 : // initializer. Such initializations don't mean anything anyhow.
1777 23672 : if (int_size_in_bytes (TREE_TYPE (var_tree)) != 0 && init_tree != NULL_TREE
1778 11668 : && TREE_TYPE (init_tree) != void_type_node
1779 23672 : && int_size_in_bytes (TREE_TYPE (init_tree)) != 0)
1780 : {
1781 11665 : DECL_INITIAL (var_tree) = init_tree;
1782 11665 : init_tree = NULL_TREE;
1783 : }
1784 :
1785 12004 : tree ret = build1_loc (DECL_SOURCE_LOCATION (var_tree), DECL_EXPR,
1786 : void_type_node, var_tree);
1787 12004 : if (init_tree != NULL_TREE)
1788 339 : ret = build2_loc (DECL_SOURCE_LOCATION (var_tree), COMPOUND_EXPR,
1789 : void_type_node, init_tree, ret);
1790 :
1791 : return ret;
1792 : }
1793 :
1794 : // Assignment.
1795 :
1796 : tree
1797 26288 : assignment_statement (tree lhs, tree rhs, location_t location)
1798 : {
1799 26288 : if (error_operand_p (lhs) || error_operand_p (rhs))
1800 4 : return error_mark_node;
1801 :
1802 : // To avoid problems with GNU ld, we don't make zero-sized
1803 : // externally visible variables. That might lead us to doing an
1804 : // assignment of a zero-sized expression to a non-zero sized
1805 : // expression; avoid crashes here by avoiding assignments of
1806 : // zero-sized expressions. Such assignments don't really mean
1807 : // anything anyhow.
1808 26284 : if (TREE_TYPE (lhs) == void_type_node
1809 26284 : || int_size_in_bytes (TREE_TYPE (lhs)) == 0
1810 21515 : || TREE_TYPE (rhs) == void_type_node
1811 47796 : || int_size_in_bytes (TREE_TYPE (rhs)) == 0)
1812 4846 : return compound_statement (lhs, rhs);
1813 :
1814 21438 : rhs = convert_tree (TREE_TYPE (lhs), rhs, location);
1815 :
1816 21438 : return fold_build2_loc (location, MODIFY_EXPR, void_type_node, lhs, rhs);
1817 : }
1818 :
1819 : // Return.
1820 :
1821 : tree
1822 19720 : return_statement (tree fntree, tree val, location_t location)
1823 : {
1824 19720 : if (error_operand_p (fntree))
1825 0 : return error_mark_node;
1826 :
1827 19720 : tree result = DECL_RESULT (fntree);
1828 19720 : if (error_operand_p (result))
1829 0 : return error_mark_node;
1830 :
1831 19720 : if (error_operand_p (val))
1832 9 : return error_mark_node;
1833 :
1834 19711 : tree set
1835 19711 : = fold_build2_loc (location, MODIFY_EXPR, void_type_node, result, val);
1836 19711 : return fold_build1_loc (location, RETURN_EXPR, void_type_node, set);
1837 : }
1838 :
1839 : // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an
1840 : // error occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and if not
1841 : // NULL, it will always be executed. This is used for handling defers in Rust
1842 : // functions. In C++, the resulting code is of this form:
1843 : // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
1844 :
1845 : tree
1846 54 : exception_handler_statement (tree try_stmt, tree except_stmt, tree finally_stmt,
1847 : location_t location)
1848 : {
1849 108 : if (error_operand_p (try_stmt) || error_operand_p (except_stmt)
1850 108 : || error_operand_p (finally_stmt))
1851 0 : return error_mark_node;
1852 :
1853 54 : if (except_stmt != NULL_TREE)
1854 2 : try_stmt = build2_loc (location, TRY_CATCH_EXPR, void_type_node, try_stmt,
1855 : build2_loc (location, CATCH_EXPR, void_type_node,
1856 : NULL, except_stmt));
1857 54 : if (finally_stmt != NULL_TREE)
1858 52 : try_stmt = build2_loc (location, TRY_FINALLY_EXPR, void_type_node, try_stmt,
1859 : finally_stmt);
1860 : return try_stmt;
1861 : }
1862 :
1863 : // If.
1864 :
1865 : tree
1866 4845 : if_statement (tree, tree cond_tree, tree then_tree, tree else_tree,
1867 : location_t location)
1868 : {
1869 9690 : if (error_operand_p (cond_tree) || error_operand_p (then_tree)
1870 9690 : || error_operand_p (else_tree))
1871 0 : return error_mark_node;
1872 4845 : tree ret = build3_loc (location, COND_EXPR, void_type_node, cond_tree,
1873 : then_tree, else_tree);
1874 4845 : return ret;
1875 : }
1876 :
1877 : // Loops
1878 :
1879 : tree
1880 349 : loop_expression (tree body, location_t locus)
1881 : {
1882 349 : return fold_build1_loc (locus, LOOP_EXPR, void_type_node, body);
1883 : }
1884 :
1885 : tree
1886 282 : exit_expression (tree cond_tree, location_t locus)
1887 : {
1888 282 : return fold_build1_loc (locus, EXIT_EXPR, void_type_node, cond_tree);
1889 : }
1890 :
1891 : // Pair of statements.
1892 :
1893 : tree
1894 4880 : compound_statement (tree s1, tree s2)
1895 : {
1896 4880 : if (error_operand_p (s1) || error_operand_p (s2))
1897 0 : return error_mark_node;
1898 :
1899 4880 : tree stmt_list = NULL_TREE;
1900 4880 : append_to_statement_list (s1, &stmt_list);
1901 4880 : append_to_statement_list (s2, &stmt_list);
1902 :
1903 : // If neither statement has any side effects, stmt_list can be NULL
1904 : // at this point.
1905 4880 : if (stmt_list == NULL_TREE)
1906 4256 : stmt_list = integer_zero_node;
1907 :
1908 4880 : return stmt_list;
1909 : }
1910 :
1911 : // List of statements.
1912 :
1913 : tree
1914 311 : statement_list (const std::vector<tree> &statements)
1915 : {
1916 311 : tree stmt_list = NULL_TREE;
1917 1406 : for (tree t : statements)
1918 : {
1919 1095 : if (error_operand_p (t))
1920 0 : return error_mark_node;
1921 1095 : append_to_statement_list (t, &stmt_list);
1922 : }
1923 311 : return stmt_list;
1924 : }
1925 :
1926 : // Make a block. For some reason gcc uses a dual structure for
1927 : // blocks: BLOCK tree nodes and BIND_EXPR tree nodes. Since the
1928 : // BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in
1929 : // the Bblock.
1930 :
1931 : tree
1932 46709 : block (tree fndecl, tree enclosing, const std::vector<Bvariable *> &vars,
1933 : location_t start_location, location_t)
1934 : {
1935 46709 : tree block_tree = make_node (BLOCK);
1936 46709 : if (enclosing == NULL)
1937 : {
1938 19726 : gcc_assert (fndecl != NULL_TREE);
1939 :
1940 : // We may have already created a block for local variables when
1941 : // we take the address of a parameter.
1942 19726 : if (DECL_INITIAL (fndecl) == NULL_TREE)
1943 : {
1944 19722 : BLOCK_SUPERCONTEXT (block_tree) = fndecl;
1945 19722 : DECL_INITIAL (fndecl) = block_tree;
1946 : }
1947 : else
1948 : {
1949 4 : tree superblock_tree = DECL_INITIAL (fndecl);
1950 4 : BLOCK_SUPERCONTEXT (block_tree) = superblock_tree;
1951 4 : tree *pp;
1952 6 : for (pp = &BLOCK_SUBBLOCKS (superblock_tree); *pp != NULL_TREE;
1953 2 : pp = &BLOCK_CHAIN (*pp))
1954 : ;
1955 4 : *pp = block_tree;
1956 : }
1957 : }
1958 : else
1959 : {
1960 26983 : tree superblock_tree = BIND_EXPR_BLOCK (enclosing);
1961 26983 : gcc_assert (TREE_CODE (superblock_tree) == BLOCK);
1962 :
1963 26983 : BLOCK_SUPERCONTEXT (block_tree) = superblock_tree;
1964 26983 : tree *pp;
1965 38985 : for (pp = &BLOCK_SUBBLOCKS (superblock_tree); *pp != NULL_TREE;
1966 12002 : pp = &BLOCK_CHAIN (*pp))
1967 : ;
1968 26983 : *pp = block_tree;
1969 : }
1970 :
1971 : // Chain the variables of the scope together so they are all connected
1972 : // to the block.
1973 46709 : tree *pp = &BLOCK_VARS (block_tree);
1974 47182 : for (Bvariable *bv : vars)
1975 : {
1976 473 : *pp = bv->get_decl ();
1977 473 : if (!error_operand_p (*pp))
1978 473 : pp = &DECL_CHAIN (*pp);
1979 : }
1980 46709 : *pp = NULL_TREE;
1981 :
1982 46709 : TREE_USED (block_tree) = 1;
1983 :
1984 46709 : tree bind_tree = build3_loc (start_location, BIND_EXPR, void_type_node,
1985 46709 : BLOCK_VARS (block_tree), NULL_TREE, block_tree);
1986 46709 : TREE_SIDE_EFFECTS (bind_tree) = 1;
1987 46709 : return bind_tree;
1988 : }
1989 :
1990 : // Add statements to a block.
1991 :
1992 : void
1993 46693 : block_add_statements (tree bind_tree, const std::vector<tree> &statements)
1994 : {
1995 46693 : tree stmt_list = NULL_TREE;
1996 175174 : for (tree s : statements)
1997 : {
1998 128481 : if (!error_operand_p (s))
1999 128410 : append_to_statement_list (s, &stmt_list);
2000 : }
2001 :
2002 46693 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
2003 46693 : BIND_EXPR_BODY (bind_tree) = stmt_list;
2004 46693 : }
2005 :
2006 : // This is not static because we declare it with GTY(()) in rust-c.h.
2007 : tree rust_non_zero_struct;
2008 :
2009 : // Return a type corresponding to TYPE with non-zero size.
2010 :
2011 : tree
2012 5 : non_zero_size_type (tree type)
2013 : {
2014 5 : if (int_size_in_bytes (type) != 0)
2015 : return type;
2016 :
2017 5 : switch (TREE_CODE (type))
2018 : {
2019 5 : case RECORD_TYPE:
2020 5 : if (TYPE_FIELDS (type) != NULL_TREE)
2021 : {
2022 0 : tree ns = make_node (RECORD_TYPE);
2023 0 : tree field_trees = NULL_TREE;
2024 0 : tree *pp = &field_trees;
2025 0 : for (tree field = TYPE_FIELDS (type); field != NULL_TREE;
2026 0 : field = DECL_CHAIN (field))
2027 : {
2028 0 : tree ft = TREE_TYPE (field);
2029 0 : if (field == TYPE_FIELDS (type))
2030 0 : ft = non_zero_size_type (ft);
2031 0 : tree f = build_decl (DECL_SOURCE_LOCATION (field), FIELD_DECL,
2032 0 : DECL_NAME (field), ft);
2033 0 : DECL_CONTEXT (f) = ns;
2034 0 : *pp = f;
2035 0 : pp = &DECL_CHAIN (f);
2036 : }
2037 0 : TYPE_FIELDS (ns) = field_trees;
2038 0 : layout_type (ns);
2039 0 : return ns;
2040 : }
2041 :
2042 5 : if (rust_non_zero_struct == NULL_TREE)
2043 : {
2044 4 : type = make_node (RECORD_TYPE);
2045 4 : tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
2046 : get_identifier ("dummy"), boolean_type_node);
2047 4 : DECL_CONTEXT (field) = type;
2048 4 : TYPE_FIELDS (type) = field;
2049 4 : layout_type (type);
2050 4 : rust_non_zero_struct = type;
2051 : }
2052 5 : return rust_non_zero_struct;
2053 :
2054 0 : case ARRAY_TYPE:
2055 0 : {
2056 0 : tree element_type = non_zero_size_type (TREE_TYPE (type));
2057 0 : return build_array_type_nelts (element_type, 1);
2058 : }
2059 :
2060 0 : default:
2061 0 : rust_unreachable ();
2062 : }
2063 :
2064 : rust_unreachable ();
2065 : }
2066 :
2067 : // Convert EXPR_TREE to TYPE_TREE. Sometimes the same unnamed Rust type
2068 : // can be created multiple times and thus have multiple tree
2069 : // representations. Make sure this does not confuse the middle-end.
2070 :
2071 : tree
2072 43702 : convert_tree (tree type_tree, tree expr_tree, location_t location)
2073 : {
2074 43702 : if (type_tree == TREE_TYPE (expr_tree))
2075 : return expr_tree;
2076 :
2077 9637 : if (error_operand_p (type_tree) || error_operand_p (expr_tree))
2078 0 : return error_mark_node;
2079 :
2080 9637 : if (POINTER_TYPE_P (type_tree) || INTEGRAL_TYPE_P (type_tree)
2081 9637 : || SCALAR_FLOAT_TYPE_P (type_tree) || COMPLEX_FLOAT_TYPE_P (type_tree))
2082 8492 : return fold_convert_loc (location, type_tree, expr_tree);
2083 1145 : else if (TREE_CODE (type_tree) == RECORD_TYPE
2084 : || TREE_CODE (type_tree) == UNION_TYPE
2085 1145 : || TREE_CODE (type_tree) == ARRAY_TYPE || VECTOR_TYPE_P (type_tree))
2086 : {
2087 1145 : gcc_assert (int_size_in_bytes (type_tree)
2088 : == int_size_in_bytes (TREE_TYPE (expr_tree)));
2089 1145 : if (TYPE_MAIN_VARIANT (type_tree)
2090 1145 : == TYPE_MAIN_VARIANT (TREE_TYPE (expr_tree)))
2091 1113 : return fold_build1_loc (location, NOP_EXPR, type_tree, expr_tree);
2092 32 : return fold_build1_loc (location, VIEW_CONVERT_EXPR, type_tree,
2093 32 : expr_tree);
2094 : }
2095 :
2096 0 : rust_unreachable ();
2097 : }
2098 :
2099 : // Make a global variable.
2100 :
2101 : Bvariable *
2102 240 : global_variable (GGC::Ident var_name, GGC::Ident asm_name, tree type_tree,
2103 : bool is_external, bool is_hidden, bool in_unique_section,
2104 : location_t location)
2105 : {
2106 240 : if (error_operand_p (type_tree))
2107 0 : return Bvariable::error_variable ();
2108 :
2109 : // The GNU linker does not like dynamic variables with zero size.
2110 240 : tree orig_type_tree = type_tree;
2111 240 : if ((is_external || !is_hidden) && int_size_in_bytes (type_tree) == 0)
2112 5 : type_tree = non_zero_size_type (type_tree);
2113 :
2114 240 : tree decl = build_decl (location, VAR_DECL, var_name.as_tree (), type_tree);
2115 240 : if (is_external)
2116 0 : DECL_EXTERNAL (decl) = 1;
2117 : else
2118 240 : TREE_STATIC (decl) = 1;
2119 240 : if (!is_hidden)
2120 : {
2121 73 : TREE_PUBLIC (decl) = 1;
2122 73 : SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ());
2123 : }
2124 : else
2125 : {
2126 167 : SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ());
2127 : }
2128 :
2129 240 : TREE_USED (decl) = 1;
2130 :
2131 240 : if (in_unique_section)
2132 240 : resolve_unique_section (decl, 0, 1);
2133 :
2134 240 : rust_preserve_from_gc (decl);
2135 :
2136 240 : return new Bvariable (decl, orig_type_tree);
2137 : }
2138 :
2139 : // Set the initial value of a global variable.
2140 :
2141 : void
2142 240 : global_variable_set_init (Bvariable *var, tree expr_tree)
2143 : {
2144 240 : if (error_operand_p (expr_tree))
2145 : return;
2146 237 : gcc_assert (TREE_CONSTANT (expr_tree));
2147 237 : tree var_decl = var->get_decl ();
2148 237 : if (error_operand_p (var_decl))
2149 : return;
2150 237 : DECL_INITIAL (var_decl) = expr_tree;
2151 :
2152 : // If this variable goes in a unique section, it may need to go into
2153 : // a different one now that DECL_INITIAL is set.
2154 237 : if (symtab_node::get (var_decl)
2155 237 : && symtab_node::get (var_decl)->implicit_section)
2156 : {
2157 237 : set_decl_section_name (var_decl, (const char *) NULL);
2158 237 : resolve_unique_section (var_decl, compute_reloc_for_constant (expr_tree),
2159 : 1);
2160 : }
2161 : }
2162 :
2163 : // Make a local variable.
2164 :
2165 : LocalVariable
2166 0 : local_variable (tree function, GGC::Ident name, tree type_tree,
2167 : Bvariable *decl_var, location_t location)
2168 : {
2169 0 : if (error_operand_p (type_tree))
2170 0 : return LocalVariable::error_variable ();
2171 0 : tree decl = build_decl (location, VAR_DECL, name.as_tree (), type_tree);
2172 0 : DECL_CONTEXT (decl) = function;
2173 :
2174 0 : if (decl_var != NULL)
2175 : {
2176 0 : DECL_HAS_VALUE_EXPR_P (decl) = 1;
2177 0 : SET_DECL_VALUE_EXPR (decl, decl_var->get_decl ());
2178 : }
2179 0 : rust_preserve_from_gc (decl);
2180 0 : return LocalVariable (decl);
2181 : }
2182 :
2183 : // Make a function parameter variable.
2184 :
2185 : LocalVariable
2186 18121 : parameter_variable (tree function, GGC::Ident name, tree type_tree,
2187 : location_t location)
2188 : {
2189 18121 : if (error_operand_p (type_tree))
2190 0 : return LocalVariable::error_variable ();
2191 18121 : tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree);
2192 18121 : DECL_CONTEXT (decl) = function;
2193 18121 : DECL_ARG_TYPE (decl) = type_tree;
2194 :
2195 18121 : rust_preserve_from_gc (decl);
2196 18121 : return LocalVariable (decl);
2197 : }
2198 :
2199 : // Make a static chain variable.
2200 :
2201 : LocalVariable
2202 0 : static_chain_variable (tree fndecl, GGC::Ident name, tree type_tree,
2203 : location_t location)
2204 : {
2205 0 : if (error_operand_p (type_tree))
2206 0 : return LocalVariable::error_variable ();
2207 0 : tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree);
2208 0 : DECL_CONTEXT (decl) = fndecl;
2209 0 : DECL_ARG_TYPE (decl) = type_tree;
2210 0 : TREE_USED (decl) = 1;
2211 0 : DECL_ARTIFICIAL (decl) = 1;
2212 0 : DECL_IGNORED_P (decl) = 1;
2213 0 : TREE_READONLY (decl) = 1;
2214 :
2215 0 : struct function *f = DECL_STRUCT_FUNCTION (fndecl);
2216 0 : if (f == NULL)
2217 : {
2218 0 : push_struct_function (fndecl);
2219 0 : pop_cfun ();
2220 0 : f = DECL_STRUCT_FUNCTION (fndecl);
2221 : }
2222 0 : gcc_assert (f->static_chain_decl == NULL);
2223 0 : f->static_chain_decl = decl;
2224 0 : DECL_STATIC_CHAIN (fndecl) = 1;
2225 :
2226 0 : rust_preserve_from_gc (decl);
2227 0 : return LocalVariable (decl);
2228 : }
2229 :
2230 : // Make a temporary variable.
2231 :
2232 : LocalVariable
2233 30124 : temporary_variable (tree fndecl, tree bind_tree, tree type_tree, tree init_tree,
2234 : bool is_address_taken, location_t location,
2235 : tree *pstatement)
2236 : {
2237 30124 : gcc_assert (fndecl != NULL_TREE);
2238 60248 : if (error_operand_p (type_tree) || error_operand_p (init_tree)
2239 60242 : || error_operand_p (fndecl))
2240 : {
2241 6 : *pstatement = error_mark_node;
2242 6 : return LocalVariable::error_variable ();
2243 : }
2244 :
2245 30118 : tree var;
2246 : // We can only use create_tmp_var if the type is not addressable.
2247 30118 : if (!TREE_ADDRESSABLE (type_tree))
2248 : {
2249 30118 : if (DECL_STRUCT_FUNCTION (fndecl) == NULL)
2250 16665 : push_struct_function (fndecl);
2251 : else
2252 13453 : push_cfun (DECL_STRUCT_FUNCTION (fndecl));
2253 :
2254 30118 : var = create_tmp_var (type_tree, "RUSTTMP");
2255 30118 : pop_cfun ();
2256 : }
2257 : else
2258 : {
2259 0 : gcc_assert (bind_tree != NULL_TREE);
2260 0 : var = build_decl (location, VAR_DECL, create_tmp_var_name ("RUSTTMP"),
2261 : type_tree);
2262 0 : DECL_ARTIFICIAL (var) = 1;
2263 0 : DECL_IGNORED_P (var) = 1;
2264 0 : TREE_USED (var) = 1;
2265 0 : DECL_CONTEXT (var) = fndecl;
2266 :
2267 : // We have to add this variable to the BLOCK and the BIND_EXPR.
2268 0 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
2269 0 : tree block_tree = BIND_EXPR_BLOCK (bind_tree);
2270 0 : gcc_assert (TREE_CODE (block_tree) == BLOCK);
2271 0 : DECL_CHAIN (var) = BLOCK_VARS (block_tree);
2272 0 : BLOCK_VARS (block_tree) = var;
2273 0 : BIND_EXPR_VARS (bind_tree) = BLOCK_VARS (block_tree);
2274 : }
2275 :
2276 52671 : if (type_size (type_tree) != 0 && init_tree != NULL_TREE
2277 35053 : && TREE_TYPE (init_tree) != void_type_node)
2278 4935 : DECL_INITIAL (var) = convert_tree (type_tree, init_tree, location);
2279 :
2280 30118 : if (is_address_taken)
2281 4805 : TREE_ADDRESSABLE (var) = 1;
2282 :
2283 30118 : *pstatement = build1_loc (location, DECL_EXPR, void_type_node, var);
2284 :
2285 : // For a zero sized type, don't initialize VAR with BINIT, but still
2286 : // evaluate BINIT for its side effects.
2287 30118 : if (init_tree != NULL_TREE
2288 30118 : && (type_size (type_tree) == 0
2289 4935 : || TREE_TYPE (init_tree) == void_type_node))
2290 34 : *pstatement = compound_statement (init_tree, *pstatement);
2291 :
2292 30118 : return LocalVariable (var);
2293 : }
2294 :
2295 : // Make a label.
2296 :
2297 : tree
2298 1431 : label (tree func_tree, tl::optional<GGC::Ident> name, location_t location)
2299 : {
2300 1431 : tree decl;
2301 1431 : if (!name.has_value ())
2302 : {
2303 1326 : if (DECL_STRUCT_FUNCTION (func_tree) == NULL)
2304 0 : push_struct_function (func_tree);
2305 : else
2306 1326 : push_cfun (DECL_STRUCT_FUNCTION (func_tree));
2307 :
2308 1326 : decl = create_artificial_label (location);
2309 :
2310 1326 : pop_cfun ();
2311 : }
2312 : else
2313 : {
2314 105 : tree id = name->as_tree ();
2315 105 : decl = build_decl (location, LABEL_DECL, id, void_type_node);
2316 105 : DECL_CONTEXT (decl) = func_tree;
2317 : }
2318 1431 : return decl;
2319 : }
2320 :
2321 : // Make a statement which defines a label.
2322 :
2323 : tree
2324 1431 : label_definition_statement (tree label)
2325 : {
2326 1431 : return fold_build1_loc (DECL_SOURCE_LOCATION (label), LABEL_EXPR,
2327 1431 : void_type_node, label);
2328 : }
2329 :
2330 : // Make a goto statement.
2331 :
2332 : tree
2333 58 : goto_statement (tree label, location_t location)
2334 : {
2335 58 : return fold_build1_loc (location, GOTO_EXPR, void_type_node, label);
2336 : }
2337 :
2338 : // Get the address of a label.
2339 :
2340 : tree
2341 0 : label_address (tree label, location_t location)
2342 : {
2343 0 : TREE_USED (label) = 1;
2344 0 : TREE_ADDRESSABLE (label) = 1;
2345 0 : tree ret = fold_convert_loc (location, ptr_type_node,
2346 : build_fold_addr_expr_loc (location, label));
2347 0 : return ret;
2348 : }
2349 :
2350 : // Declare or define a new function.
2351 :
2352 : tree
2353 20867 : function (tree functype, GGC::Ident name, tl::optional<GGC::Ident> asm_name,
2354 : unsigned int flags, location_t location)
2355 : {
2356 20867 : if (error_operand_p (functype))
2357 0 : return error_mark_node;
2358 :
2359 20867 : gcc_assert (FUNCTION_POINTER_TYPE_P (functype));
2360 20867 : functype = TREE_TYPE (functype);
2361 20867 : tree id = name.as_tree ();
2362 20867 : if (error_operand_p (id))
2363 0 : return error_mark_node;
2364 :
2365 20867 : tree decl = build_decl (location, FUNCTION_DECL, id, functype);
2366 20867 : if (asm_name.has_value ())
2367 4555 : SET_DECL_ASSEMBLER_NAME (decl, asm_name->as_tree ());
2368 :
2369 20867 : if ((flags & function_is_declaration) != 0)
2370 1141 : DECL_EXTERNAL (decl) = 1;
2371 : else
2372 : {
2373 19726 : tree restype = TREE_TYPE (functype);
2374 19726 : tree resdecl = build_decl (location, RESULT_DECL, NULL_TREE, restype);
2375 19726 : DECL_ARTIFICIAL (resdecl) = 1;
2376 19726 : DECL_IGNORED_P (resdecl) = 1;
2377 19726 : DECL_CONTEXT (resdecl) = decl;
2378 19726 : DECL_RESULT (decl) = resdecl;
2379 : }
2380 20867 : if ((flags & function_is_uninlinable) != 0)
2381 0 : DECL_UNINLINABLE (decl) = 1;
2382 20867 : if ((flags & function_does_not_return) != 0)
2383 0 : TREE_THIS_VOLATILE (decl) = 1;
2384 20867 : if ((flags & function_in_unique_section) != 0)
2385 0 : resolve_unique_section (decl, 0, 1);
2386 :
2387 20867 : rust_preserve_from_gc (decl);
2388 20867 : return decl;
2389 : }
2390 :
2391 : // Create a statement that runs all deferred calls for FUNCTION. This should
2392 : // be a statement that looks like this in C++:
2393 : // finish:
2394 : // try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
2395 :
2396 : tree
2397 0 : function_defer_statement (tree function, tree undefer_tree, tree defer_tree,
2398 : location_t location)
2399 : {
2400 0 : if (error_operand_p (undefer_tree) || error_operand_p (defer_tree)
2401 0 : || error_operand_p (function))
2402 0 : return error_mark_node;
2403 :
2404 0 : if (DECL_STRUCT_FUNCTION (function) == NULL)
2405 0 : push_struct_function (function);
2406 : else
2407 0 : push_cfun (DECL_STRUCT_FUNCTION (function));
2408 :
2409 0 : tree stmt_list = NULL;
2410 0 : tree label = Backend::label (function, tl::nullopt, location);
2411 0 : tree label_def = label_definition_statement (label);
2412 0 : append_to_statement_list (label_def, &stmt_list);
2413 :
2414 0 : tree jump_stmt = goto_statement (label, location);
2415 0 : tree catch_body
2416 0 : = build2 (COMPOUND_EXPR, void_type_node, defer_tree, jump_stmt);
2417 0 : catch_body = build2 (CATCH_EXPR, void_type_node, NULL, catch_body);
2418 0 : tree try_catch
2419 0 : = build2 (TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
2420 0 : append_to_statement_list (try_catch, &stmt_list);
2421 0 : pop_cfun ();
2422 :
2423 0 : return stmt_list;
2424 : }
2425 :
2426 : // Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
2427 : // This will only be called for a function definition.
2428 :
2429 : bool
2430 17065 : function_set_parameters (tree function,
2431 : const std::vector<Bvariable *> ¶m_vars)
2432 : {
2433 17065 : if (error_operand_p (function))
2434 : return false;
2435 :
2436 17065 : tree params = NULL_TREE;
2437 17065 : tree *pp = ¶ms;
2438 35185 : for (Bvariable *bv : param_vars)
2439 : {
2440 18121 : *pp = bv->get_decl ();
2441 18121 : gcc_assert (!error_operand_p (*pp));
2442 18120 : pp = &DECL_CHAIN (*pp);
2443 : }
2444 17064 : *pp = NULL_TREE;
2445 17064 : DECL_ARGUMENTS (function) = params;
2446 17064 : return true;
2447 : }
2448 :
2449 : // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
2450 : // FUNCTION_DECLS, and VARIABLE_DECLS declared globally, as well as
2451 : // emit early debugging information.
2452 :
2453 : void
2454 4441 : write_global_definitions (const std::vector<tree> &type_decls,
2455 : const std::vector<tree> &constant_decls,
2456 : const std::vector<tree> &function_decls,
2457 : const std::vector<Bvariable *> &variable_decls)
2458 : {
2459 4441 : size_t count_definitions = type_decls.size () + constant_decls.size ()
2460 4441 : + function_decls.size () + variable_decls.size ();
2461 :
2462 4441 : tree *defs = new tree[count_definitions];
2463 :
2464 : // Convert all non-erroneous declarations into Gimple form.
2465 4441 : size_t i = 0;
2466 9119 : for (Bvariable *bv : variable_decls)
2467 : {
2468 237 : tree v = bv->get_decl ();
2469 237 : if (error_operand_p (v))
2470 0 : continue;
2471 237 : defs[i] = v;
2472 237 : rust_preserve_from_gc (defs[i]);
2473 237 : ++i;
2474 : }
2475 :
2476 91039 : for (tree type_tree : type_decls)
2477 : {
2478 86598 : if (!error_operand_p (type_tree) && IS_TYPE_OR_DECL_P (type_tree))
2479 : {
2480 86598 : defs[i] = TYPE_NAME (type_tree);
2481 86598 : gcc_assert (defs[i] != NULL);
2482 86598 : rust_preserve_from_gc (defs[i]);
2483 86598 : ++i;
2484 : }
2485 : }
2486 4958 : for (tree t : constant_decls)
2487 : {
2488 517 : if (!error_operand_p (t))
2489 : {
2490 517 : defs[i] = t;
2491 517 : rust_preserve_from_gc (defs[i]);
2492 517 : ++i;
2493 : }
2494 : }
2495 21957 : for (tree decl : function_decls)
2496 : {
2497 17516 : if (!error_operand_p (decl))
2498 : {
2499 17516 : rust_preserve_from_gc (decl);
2500 17516 : if (DECL_STRUCT_FUNCTION (decl) == NULL)
2501 2996 : allocate_struct_function (decl, false);
2502 17516 : dump_function (TDI_original, decl);
2503 17516 : cgraph_node::finalize_function (decl, true);
2504 :
2505 17516 : defs[i] = decl;
2506 17516 : ++i;
2507 : }
2508 : }
2509 :
2510 : // Pass everything back to the middle-end.
2511 :
2512 4441 : wrapup_global_declarations (defs, i);
2513 :
2514 4441 : delete[] defs;
2515 4441 : }
2516 :
2517 : tree
2518 14 : lookup_field (const_tree type, tree component)
2519 : {
2520 14 : tree field;
2521 :
2522 21 : for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2523 : {
2524 21 : if (DECL_NAME (field) == NULL_TREE
2525 21 : && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
2526 : {
2527 0 : tree anon = lookup_field (TREE_TYPE (field), component);
2528 :
2529 0 : if (anon)
2530 0 : return tree_cons (NULL_TREE, field, anon);
2531 : }
2532 :
2533 21 : if (DECL_NAME (field) == component)
2534 : break;
2535 : }
2536 :
2537 14 : if (field == NULL_TREE)
2538 : return NULL_TREE;
2539 :
2540 14 : return tree_cons (NULL_TREE, field, NULL_TREE);
2541 : }
2542 :
2543 : } // namespace Backend
|