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