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

Generated by: LCOV version 2.5.0-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.