LCOV - code coverage report
Current view: top level - gcc/rust - rust-gcc.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 75.6 % 1053 796
Test Date: 2026-09-19 16:22:48 Functions: 82.8 % 87 72
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.