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