LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-expr.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.0 % 1842 1713
Test Date: 2026-09-19 16:22:48 Functions: 97.5 % 80 78
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-compile-expr.h"
      20              : #include "line-map.h"
      21              : #include "optional.h"
      22              : #include "rust-backend.h"
      23              : #include "rust-compile-context.h"
      24              : #include "rust-compile-type.h"
      25              : #include "rust-compile-struct-field-expr.h"
      26              : #include "rust-compile-pattern.h"
      27              : #include "rust-compile-resolve-path.h"
      28              : #include "rust-compile-block.h"
      29              : #include "rust-compile-drop.h"
      30              : #include "rust-compile-implitem.h"
      31              : #include "rust-compile-platform-intrinsic.h"
      32              : #include "rust-constexpr.h"
      33              : #include "rust-compile-type.h"
      34              : #include "rust-finalized-name-resolution-context.h"
      35              : #include "rust-gcc.h"
      36              : #include "rust-compile-asm.h"
      37              : #include "fold-const.h"
      38              : #include "realmpfr.h"
      39              : #include "convert.h"
      40              : #include "print-tree.h"
      41              : #include "rust-hir-bound.h"
      42              : #include "rust-hir-expr.h"
      43              : #include "rust-rib.h"
      44              : #include "rust-tree.h"
      45              : #include "rust-tyty.h"
      46              : #include "tree-core.h"
      47              : 
      48              : namespace Rust {
      49              : namespace Compile {
      50              : 
      51              : namespace {
      52              : tree
      53           19 : compile_box_struct (Context *ctx, TyTy::BaseType *curr_ty, tree typed_ptr,
      54              :                     location_t locus, int depth = 0)
      55              : {
      56              :   // infinite loop guard
      57           20 :   rust_assert (depth < 100);
      58              : 
      59           20 :   if (curr_ty->get_kind () == TyTy::TypeKind::POINTER
      60           20 :       || curr_ty->get_kind () == TyTy::TypeKind::REF)
      61              :     return typed_ptr;
      62              : 
      63           14 :   if (curr_ty->get_kind () == TyTy::TypeKind::ADT)
      64              :     {
      65           13 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (curr_ty);
      66           13 :       tree adt_ty_tree = TyTyResolveCompile::compile (ctx, adt);
      67           13 :       tree size_tree = TYPE_SIZE_UNIT (adt_ty_tree);
      68              : 
      69           13 :       if (integer_zerop (size_tree))
      70            3 :         return Backend::constructor_expression (adt_ty_tree, false, {}, -1,
      71              :                                                 locus);
      72           10 :       rust_assert (!adt->is_enum ());
      73           10 :       rust_assert (adt->number_of_variants () == 1);
      74              : 
      75           10 :       std::vector<tree> args;
      76           10 :       TyTy::VariantDef *variant = adt->get_variants ().at (0);
      77           23 :       for (size_t i = 0; i < variant->num_fields (); i++)
      78              :         {
      79           13 :           TyTy::StructFieldType *field = variant->get_field_at_index (i);
      80           13 :           TyTy::BaseType *field_ty = field->get_field_type ();
      81           13 :           tree field_tree
      82           13 :             = compile_box_struct (ctx, field_ty, typed_ptr, locus, depth + 1);
      83           13 :           args.push_back (field_tree);
      84              :         }
      85           10 :       return Backend::constructor_expression (adt_ty_tree, false, args, -1,
      86              :                                               locus);
      87           10 :     }
      88            1 :   if (curr_ty->get_kind () == TyTy::TypeKind::PARAM)
      89              :     {
      90            1 :       TyTy::ParamType *param_ty = static_cast<TyTy::ParamType *> (curr_ty);
      91            1 :       TyTy::BaseType *resolved_ty = param_ty->resolve ();
      92            1 :       rust_assert (resolved_ty != nullptr && resolved_ty != curr_ty);
      93            1 :       return compile_box_struct (ctx, resolved_ty, typed_ptr, locus, depth + 1);
      94              :     }
      95            0 :   rust_unreachable ();
      96              :   return error_mark_node;
      97              : };
      98              : 
      99              : tree
     100            6 : compile_box (Context *ctx, TyTy::BaseType *box_tyty, TyTy::BaseType *inner_tyty,
     101              :              tree inner_expr_tree, location_t locus)
     102              : {
     103            6 :   tree inner_type_tree = TyTyResolveCompile::compile (ctx, inner_tyty);
     104              : 
     105            6 :   tree size_tree = TYPE_SIZE_UNIT (inner_type_tree);
     106            6 :   tree align_tree
     107            6 :     = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (inner_type_tree));
     108              : 
     109            6 :   DefId exchange_malloc_defid
     110            6 :     = ctx->get_mappings ().get_lang_item (LangItem::Kind::EXCHANGE_MALLOC,
     111              :                                           locus);
     112            6 :   HIR::Item *item
     113            6 :     = ctx->get_mappings ().lookup_defid (exchange_malloc_defid).value ();
     114              : 
     115            6 :   tree exchange_malloc_decl = nullptr;
     116            6 :   ctx->lookup_function_decl (item->get_mappings ().get_hirid (),
     117              :                              &exchange_malloc_decl, exchange_malloc_defid);
     118              : 
     119            6 :   tree raw_ptr = save_expr (build_call_expr_loc (locus, exchange_malloc_decl, 2,
     120              :                                                  size_tree, align_tree));
     121            6 :   tree typed_ptr = fold_convert (build_pointer_type (inner_type_tree), raw_ptr);
     122              : 
     123            6 :   tree deref = build1_loc (locus, INDIRECT_REF, inner_type_tree, typed_ptr);
     124            6 :   tree assignment
     125            6 :     = build2_loc (locus, MODIFY_EXPR, inner_type_tree, deref, inner_expr_tree);
     126              : 
     127            6 :   tree box_struct = compile_box_struct (ctx, box_tyty, typed_ptr, locus);
     128              : 
     129            6 :   return build2_loc (locus, COMPOUND_EXPR, TREE_TYPE (box_struct), assignment,
     130            6 :                      box_struct);
     131              : }
     132              : 
     133              : tree
     134           16 : build_box_inner_ptr (tree main_expr, location_t locus)
     135              : {
     136              :   // We continuously extract the first field of the struct until we hit the
     137              :   // actual underlying raw pointer. This handles both simple Box layouts (ptr:
     138              :   // *mut T) and complex ones like this (Box<Unique<NonNull<T>>>). This relies
     139              :   // on the standard library's layout guarantees and will break if a stateful
     140              :   // custom allocator is placed as the first field in the RECORD_TYPE.
     141           42 :   while (TREE_CODE (TREE_TYPE (main_expr)) == RECORD_TYPE)
     142              :     {
     143           31 :       if (RS_DST_FLAG_P (TREE_TYPE (main_expr)))
     144              :         break;
     145              : 
     146           26 :       tree first_field = TYPE_FIELDS (TREE_TYPE (main_expr));
     147           26 :       if (first_field == NULL_TREE)
     148              :         break;
     149           26 :       main_expr = build3_loc (locus, COMPONENT_REF, TREE_TYPE (first_field),
     150              :                               main_expr, first_field, NULL_TREE);
     151              :     }
     152           16 :   return main_expr;
     153              : }
     154              : } // namespace
     155              : 
     156       130120 : CompileExpr::CompileExpr (Context *ctx)
     157       130120 :   : HIRCompileBase (ctx), translated (error_mark_node)
     158       130120 : {}
     159              : 
     160              : tree
     161       130120 : CompileExpr::Compile (HIR::Expr &expr, Context *ctx)
     162              : {
     163       130120 :   CompileExpr compiler (ctx);
     164       130120 :   expr.accept_vis (compiler);
     165       130120 :   return compiler.translated;
     166       130120 : }
     167              : 
     168              : void
     169          893 : CompileExpr::visit (HIR::TupleIndexExpr &expr)
     170              : {
     171          893 :   HIR::Expr &tuple_expr = expr.get_tuple_expr ();
     172          893 :   TupleIndex index = expr.get_tuple_index ();
     173              : 
     174          893 :   tree receiver_ref = CompileExpr::Compile (tuple_expr, ctx);
     175              : 
     176          893 :   TyTy::BaseType *tuple_expr_ty = nullptr;
     177          893 :   bool ok
     178          893 :     = ctx->get_tyctx ()->lookup_type (tuple_expr.get_mappings ().get_hirid (),
     179              :                                       &tuple_expr_ty);
     180          893 :   rust_assert (ok);
     181              : 
     182              :   // do we need to add an indirect reference
     183          893 :   if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF)
     184              :     {
     185          299 :       tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
     186          299 :       receiver_ref = indirect;
     187              :     }
     188          594 :   else if (auto inner_expr_ty = TyTy::try_get_box_inner_type (tuple_expr_ty))
     189              :     {
     190            2 :       rust_assert (inner_expr_ty.value ()->get_kind ()
     191              :                    == TyTy::TypeKind::TUPLE);
     192            2 :       receiver_ref = build_box_inner_ptr (receiver_ref, expr.get_locus ());
     193            2 :       receiver_ref = indirect_expression (receiver_ref, expr.get_locus ());
     194              :     }
     195              : 
     196          893 :   translated
     197          893 :     = Backend::struct_field_expression (receiver_ref, index, expr.get_locus ());
     198          893 : }
     199              : 
     200              : void
     201          626 : CompileExpr::visit (HIR::TupleExpr &expr)
     202              : {
     203          626 :   if (expr.is_unit ())
     204              :     {
     205          140 :       translated = unit_expression (expr.get_locus ());
     206          140 :       return;
     207              :     }
     208              : 
     209          486 :   TyTy::BaseType *tyty = nullptr;
     210          486 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     211              :                                        &tyty))
     212              :     {
     213            0 :       rust_fatal_error (expr.get_locus (),
     214              :                         "did not resolve type for this TupleExpr");
     215              :       return;
     216              :     }
     217              : 
     218          486 :   tree tuple_type = TyTyResolveCompile::compile (ctx, tyty);
     219          486 :   rust_assert (tuple_type != nullptr);
     220              : 
     221              :   // this assumes all fields are in order from type resolution
     222          486 :   std::vector<tree> vals;
     223         1589 :   for (auto &elem : expr.get_tuple_elems ())
     224              :     {
     225         1103 :       auto e = CompileExpr::Compile (*elem, ctx);
     226         1103 :       vals.push_back (e);
     227              :     }
     228              : 
     229          486 :   translated = Backend::constructor_expression (tuple_type, false, vals, -1,
     230              :                                                 expr.get_locus ());
     231          486 : }
     232              : 
     233              : void
     234            6 : CompileExpr::visit (HIR::BoxExpr &expr)
     235              : {
     236            6 :   TyTy::BaseType *inner_tyty = nullptr;
     237            6 :   bool ok = ctx->get_tyctx ()->lookup_type (
     238            6 :     expr.get_expr ().get_mappings ().get_hirid (), &inner_tyty);
     239            6 :   rust_assert (ok);
     240              : 
     241            6 :   TyTy::BaseType *box_tyty = nullptr;
     242            6 :   ok = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     243              :                                        &box_tyty);
     244            6 :   rust_assert (ok);
     245              : 
     246            6 :   tree inner_expr_tree
     247            6 :     = save_expr (CompileExpr::Compile (expr.get_expr (), ctx));
     248              : 
     249            6 :   translated = compile_box (ctx, box_tyty, inner_tyty, inner_expr_tree,
     250              :                             expr.get_locus ());
     251            6 : }
     252              : 
     253              : void
     254          564 : CompileExpr::visit (HIR::ReturnExpr &expr)
     255              : {
     256          564 :   auto fncontext = ctx->peek_fn ();
     257              : 
     258          564 :   tree return_value = expr.has_return_expr ()
     259          564 :                         ? CompileExpr::Compile (expr.get_expr (), ctx)
     260           43 :                         : unit_expression (expr.get_locus ());
     261              : 
     262          564 :   if (expr.has_return_expr ())
     263              :     {
     264          521 :       HirId id = expr.get_mappings ().get_hirid ();
     265          521 :       location_t rvalue_locus = expr.return_expr->get_locus ();
     266              : 
     267          521 :       TyTy::BaseType *expected = fncontext.retty;
     268          521 :       location_t lvalue_locus
     269          521 :         = ctx->get_mappings ().lookup_location (expected->get_ref ());
     270              : 
     271          521 :       TyTy::BaseType *actual = nullptr;
     272          521 :       bool ok = ctx->get_tyctx ()->lookup_type (
     273          521 :         expr.return_expr->get_mappings ().get_hirid (), &actual);
     274          521 :       rust_assert (ok);
     275              : 
     276          521 :       return_value = coercion_site (id, return_value, actual, expected,
     277              :                                     lvalue_locus, rvalue_locus);
     278              :     }
     279              : 
     280          564 :   if (fncontext.retty->is_unit ())
     281              :     {
     282           52 :       if (expr.has_return_expr ())
     283              :         {
     284            9 :           ctx->add_statement (return_value);
     285            9 :           return_value = unit_expression (expr.get_locus ());
     286              :         }
     287              :     }
     288          512 :   else if (expr.has_return_expr ())
     289              :     {
     290          512 :       tree result_reference
     291          512 :         = Backend::var_expression (fncontext.ret_addr, expr.get_locus ());
     292              : 
     293          512 :       tree assignment
     294          512 :         = Backend::assignment_statement (result_reference, return_value,
     295              :                                          expr.get_locus ());
     296              : 
     297          512 :       ctx->add_statement (assignment);
     298          512 :       return_value
     299          512 :         = Backend::var_expression (fncontext.ret_addr, expr.get_locus ());
     300              :     }
     301              : 
     302          564 :   tree return_stmt = Backend::return_statement (fncontext.fndecl, return_value,
     303              :                                                 expr.get_locus ());
     304              : 
     305          564 :   translated = return_stmt;
     306          564 : }
     307              : 
     308              : void
     309         3750 : CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
     310              : {
     311         3750 :   auto op = expr.get_expr_type ();
     312         3750 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     313         3750 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     314              : 
     315              :   // this might be an operator overload situation lets check
     316         3750 :   TyTy::FnType *fntype;
     317         3750 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     318         3750 :     expr.get_mappings ().get_hirid (), &fntype);
     319         3750 :   if (is_op_overload)
     320              :     {
     321          201 :       auto lang_item_type
     322          201 :         = LangItem::OperatorToLangItem (expr.get_expr_type ());
     323          201 :       translated = resolve_operator_overload (
     324          402 :         lang_item_type, expr, lhs, rhs, expr.get_lhs (),
     325          201 :         tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()));
     326          477 :       return;
     327              :     }
     328              : 
     329         3549 :   bool can_generate_overflow_checks
     330         3549 :     = (ctx->in_fn () && !ctx->const_context_p ()) && flag_overflow_checks;
     331         3549 :   if (!can_generate_overflow_checks)
     332              :     {
     333          276 :       translated
     334          276 :         = Backend::arithmetic_or_logical_expression (op, lhs, rhs,
     335              :                                                      expr.get_locus ());
     336          276 :       return;
     337              :     }
     338              : 
     339         3273 :   auto receiver_tmp = NULL_TREE;
     340         3273 :   Bvariable *receiver
     341         3273 :     = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
     342         3273 :                                    TREE_TYPE (lhs), lhs, true,
     343              :                                    expr.get_locus (), &receiver_tmp);
     344         3273 :   auto check
     345         3273 :     = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs,
     346              :                                                          expr.get_locus (),
     347              :                                                          receiver);
     348              : 
     349         3273 :   ctx->add_statement (check);
     350         3273 :   translated = receiver->get_tree (expr.get_locus ());
     351              : }
     352              : 
     353              : void
     354          780 : CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
     355              : {
     356          780 :   auto op = expr.get_expr_type ();
     357          780 :   tree lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     358          780 :   tree rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     359          780 :   tree compound_assignment = NULL_TREE;
     360              :   // this might be an operator overload situation lets check
     361          780 :   TyTy::FnType *fntype;
     362          780 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     363          780 :     expr.get_mappings ().get_hirid (), &fntype);
     364          780 :   if (is_op_overload)
     365              :     {
     366           14 :       auto lang_item_type = LangItem::CompoundAssignmentOperatorToLangItem (
     367              :         expr.get_expr_type ());
     368           14 :       compound_assignment
     369           14 :         = resolve_operator_overload (lang_item_type, expr, lhs, rhs,
     370           14 :                                      expr.get_lhs (), expr.get_rhs ());
     371              :     }
     372          766 :   else if (ctx->in_fn () && !ctx->const_context_p ())
     373              :     {
     374          763 :       tree tmp = NULL_TREE;
     375          763 :       Bvariable *receiver
     376          763 :         = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
     377          763 :                                        TREE_TYPE (lhs), lhs, true,
     378              :                                        expr.get_locus (), &tmp);
     379          763 :       tree check
     380          763 :         = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs,
     381              :                                                              expr.get_locus (),
     382              :                                                              receiver);
     383          763 :       ctx->add_statement (check);
     384          763 :       compound_assignment
     385          763 :         = Backend::assignment_statement (lhs,
     386              :                                          receiver->get_tree (expr.get_locus ()),
     387              :                                          expr.get_locus ());
     388              :     }
     389              :   else
     390              :     {
     391            3 :       tree expr_tree
     392            3 :         = Backend::arithmetic_or_logical_expression (op, lhs, rhs,
     393              :                                                      expr.get_locus ());
     394            3 :       compound_assignment
     395            3 :         = Backend::assignment_statement (lhs, expr_tree, expr.get_locus ());
     396              :     }
     397          780 :   ctx->add_statement (compound_assignment);
     398          780 :   translated = unit_expression (expr.get_locus ());
     399          780 : }
     400              : 
     401              : void
     402          853 : CompileExpr::visit (HIR::NegationExpr &expr)
     403              : {
     404          853 :   auto op = expr.get_expr_type ();
     405              : 
     406          853 :   auto &literal_expr = expr.get_expr ();
     407              : 
     408              :   // If it's a negated integer/float literal, we can return early
     409          853 :   if (op == NegationOperator::NEGATE
     410          853 :       && literal_expr.get_expression_type () == HIR::Expr::ExprType::Lit)
     411              :     {
     412          629 :       auto &new_literal_expr = static_cast<HIR::LiteralExpr &> (literal_expr);
     413          629 :       auto lit_type = new_literal_expr.get_lit_type ();
     414          629 :       if (lit_type == HIR::Literal::LitType::INT
     415          629 :           || lit_type == HIR::Literal::LitType::FLOAT)
     416              :         {
     417          629 :           new_literal_expr.set_negative ();
     418          629 :           translated = CompileExpr::Compile (literal_expr, ctx);
     419          643 :           return;
     420              :         }
     421              :     }
     422              : 
     423          224 :   auto negated_expr = CompileExpr::Compile (literal_expr, ctx);
     424          224 :   auto location = expr.get_locus ();
     425              : 
     426              :   // this might be an operator overload situation lets check
     427          224 :   TyTy::FnType *fntype;
     428          224 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     429          224 :     expr.get_mappings ().get_hirid (), &fntype);
     430          224 :   if (is_op_overload)
     431              :     {
     432           14 :       auto lang_item_type = LangItem::NegationOperatorToLangItem (op);
     433           14 :       translated
     434           14 :         = resolve_operator_overload (lang_item_type, expr, negated_expr,
     435              :                                      nullptr, expr.get_expr (), tl::nullopt);
     436           14 :       return;
     437              :     }
     438              : 
     439          210 :   translated = Backend::negation_expression (op, negated_expr, location);
     440              : }
     441              : 
     442              : void
     443         3586 : CompileExpr::visit (HIR::ComparisonExpr &expr)
     444              : {
     445         3586 :   auto op = expr.get_expr_type ();
     446         3586 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     447         3586 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     448         3586 :   auto location = expr.get_locus ();
     449              : 
     450              :   // this might be an operator overload situation lets check
     451         3586 :   TyTy::FnType *fntype;
     452         3586 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     453         3586 :     expr.get_mappings ().get_hirid (), &fntype);
     454         3586 :   if (is_op_overload)
     455              :     {
     456          875 :       auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
     457         1750 :       auto segment = HIR::PathIdentSegment (seg_name);
     458          875 :       auto lang_item_type
     459          875 :         = LangItem::ComparisonToLangItem (expr.get_expr_type ());
     460              : 
     461          875 :       rhs = address_expression (rhs, EXPR_LOCATION (rhs));
     462              : 
     463         1750 :       translated = resolve_operator_overload (
     464         1750 :         lang_item_type, expr, lhs, rhs, expr.get_lhs (),
     465          875 :         tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()),
     466              :         segment);
     467          875 :       return;
     468          875 :     }
     469              : 
     470         2711 :   translated = Backend::comparison_expression (op, lhs, rhs, location);
     471              : }
     472              : 
     473              : void
     474          417 : CompileExpr::visit (HIR::LazyBooleanExpr &expr)
     475              : {
     476          417 :   auto op = expr.get_expr_type ();
     477          417 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     478          417 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     479          417 :   auto location = expr.get_locus ();
     480              : 
     481          417 :   translated = Backend::lazy_boolean_expression (op, lhs, rhs, location);
     482          417 : }
     483              : 
     484              : void
     485         5380 : CompileExpr::visit (HIR::TypeCastExpr &expr)
     486              : {
     487         5380 :   TyTy::BaseType *type_to_cast_to_ty = nullptr;
     488         5380 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     489              :                                        &type_to_cast_to_ty))
     490              :     {
     491            0 :       translated = error_mark_node;
     492            0 :       return;
     493              :     }
     494              : 
     495         5380 :   TyTy::BaseType *casted_tyty = nullptr;
     496         5380 :   if (!ctx->get_tyctx ()->lookup_type (
     497         5380 :         expr.get_casted_expr ().get_mappings ().get_hirid (), &casted_tyty))
     498              :     {
     499            0 :       translated = error_mark_node;
     500            0 :       return;
     501              :     }
     502              : 
     503         5380 :   auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty);
     504         5380 :   auto casted_expr = CompileExpr::Compile (expr.get_casted_expr (), ctx);
     505              : 
     506         5380 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
     507         5380 :   bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings (
     508         5380 :     expr.get_mappings ().get_hirid (), &adjustments);
     509         5380 :   if (ok)
     510              :     {
     511         5380 :       casted_expr
     512         5380 :         = resolve_adjustments (*adjustments, casted_expr, expr.get_locus ());
     513              :     }
     514              : 
     515         5380 :   translated
     516         5380 :     = type_cast_expression (type_to_cast_to, casted_expr, expr.get_locus ());
     517              : }
     518              : 
     519              : void
     520         1269 : CompileExpr::visit (HIR::IfExpr &expr)
     521              : {
     522         1269 :   auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr);
     523         1269 :   ctx->add_statement (stmt);
     524         1269 :   translated = unit_expression (expr.get_locus ());
     525         1269 : }
     526              : 
     527              : void
     528           26 : CompileExpr::visit (HIR::InlineAsm &expr)
     529              : {
     530           26 :   CompileAsm asm_codegen (ctx);
     531           26 :   ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
     532           26 :   translated = unit_expression (expr.get_locus ());
     533           26 : }
     534              : 
     535              : void
     536            2 : CompileExpr::visit (HIR::LlvmInlineAsm &expr)
     537              : {
     538            2 :   CompileLlvmAsm asm_codegen (ctx);
     539            2 :   ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
     540            2 :   translated = unit_expression (expr.get_locus ());
     541            2 : }
     542              : 
     543              : void
     544           14 : CompileExpr::visit (HIR::OffsetOf &expr)
     545              : {
     546           14 :   TyTy::BaseType *type = nullptr;
     547           14 :   if (!ctx->get_tyctx ()->lookup_type (
     548           14 :         expr.get_type ().get_mappings ().get_hirid (), &type))
     549              :     {
     550            0 :       translated = error_mark_node;
     551            0 :       return;
     552              :     }
     553              : 
     554           14 :   auto compiled_ty = TyTyResolveCompile::compile (ctx, type);
     555              : 
     556           14 :   rust_assert (TREE_CODE (compiled_ty) == RECORD_TYPE);
     557              : 
     558              :   // Create an identifier node for the field
     559           14 :   auto field_id = Backend::get_identifier_node (expr.get_field ().as_string ());
     560              : 
     561              :   // And now look it up and get its value for `byte_position`
     562           14 :   auto field = Backend::lookup_field (compiled_ty, field_id);
     563           14 :   auto field_value = TREE_VALUE (field);
     564              : 
     565           14 :   translated = byte_position (field_value);
     566              : }
     567              : 
     568              : void
     569          892 : CompileExpr::visit (HIR::IfExprConseqElse &expr)
     570              : {
     571          892 :   TyTy::BaseType *if_type = nullptr;
     572          892 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     573              :                                        &if_type))
     574              :     {
     575            0 :       rust_error_at (expr.get_locus (),
     576              :                      "failed to lookup type of IfExprConseqElse");
     577            0 :       return;
     578              :     }
     579              : 
     580          892 :   Bvariable *tmp = NULL;
     581          892 :   fncontext fnctx = ctx->peek_fn ();
     582          892 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     583          892 :   tree block_type = TyTyResolveCompile::compile (ctx, if_type);
     584              : 
     585          892 :   bool is_address_taken = false;
     586          892 :   tree ret_var_stmt = nullptr;
     587          892 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     588              :                                      NULL, is_address_taken, expr.get_locus (),
     589              :                                      &ret_var_stmt);
     590          892 :   ctx->add_statement (ret_var_stmt);
     591              : 
     592          892 :   auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
     593          892 :   ctx->add_statement (stmt);
     594              : 
     595          892 :   translated = Backend::var_expression (tmp, expr.get_locus ());
     596              : }
     597              : 
     598              : void
     599         5220 : CompileExpr::visit (HIR::BlockExpr &expr)
     600              : {
     601         5220 :   TyTy::BaseType *block_tyty = nullptr;
     602         5220 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     603              :                                        &block_tyty))
     604              :     {
     605            0 :       rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
     606            0 :       return;
     607              :     }
     608              : 
     609         5220 :   Bvariable *tmp = NULL;
     610         5220 :   fncontext fnctx = ctx->peek_fn ();
     611         5220 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     612         5220 :   tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
     613         5220 :   tree block_label = NULL_TREE;
     614              : 
     615         5220 :   bool is_address_taken = false;
     616         5220 :   tree ret_var_stmt = nullptr;
     617         5220 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     618              :                                      NULL, is_address_taken, expr.get_locus (),
     619              :                                      &ret_var_stmt);
     620              : 
     621         5220 :   ctx->add_statement (ret_var_stmt);
     622              : 
     623         5220 :   if (expr.has_label ())
     624              :     {
     625            3 :       ctx->insert_var_decl (
     626            3 :         expr.get_label ().get_lifetime ().get_mappings ().get_hirid (), tmp);
     627            3 :       block_label = construct_block_label (expr);
     628              :     }
     629              : 
     630         5220 :   auto block_stmt = CompileBlock::compile (expr, ctx, tmp);
     631         5220 :   rust_assert (TREE_CODE (block_stmt) == BIND_EXPR);
     632         5220 :   ctx->add_statement (block_stmt);
     633              : 
     634         5220 :   if (block_label != NULL_TREE)
     635              :     {
     636            3 :       ctx->add_statement (block_label);
     637              :     }
     638         5220 :   translated = Backend::var_expression (tmp, expr.get_locus ());
     639              : }
     640              : 
     641              : void
     642          767 : CompileExpr::visit (HIR::AnonConst &expr)
     643              : {
     644          767 :   expr.get_inner_expr ().accept_vis (*this);
     645          767 : }
     646              : 
     647              : void
     648           15 : CompileExpr::visit (HIR::ConstBlock &expr)
     649              : {
     650           15 :   expr.get_const_expr ().accept_vis (*this);
     651           15 : }
     652              : 
     653              : void
     654         3694 : CompileExpr::visit (HIR::UnsafeBlockExpr &expr)
     655              : {
     656         3694 :   expr.get_block_expr ().accept_vis (*this);
     657         3694 : }
     658              : 
     659              : void
     660           79 : CompileExpr::visit (HIR::StructExprStruct &struct_expr)
     661              : {
     662           79 :   TyTy::BaseType *tyty = nullptr;
     663           79 :   if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
     664              :                                        &tyty))
     665              :     {
     666            0 :       rust_error_at (struct_expr.get_locus (), "unknown type");
     667            0 :       return;
     668              :     }
     669              : 
     670           79 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
     671           79 :   TyTy::VariantDef *variant = nullptr;
     672           79 :   if (adt->is_enum ())
     673              :     {
     674              :       // unwrap variant and ensure that it can be resolved
     675            3 :       HirId variant_id;
     676            3 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
     677            3 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
     678              :         &variant_id);
     679            3 :       rust_assert (ok);
     680              : 
     681            3 :       ok = adt->lookup_variant_by_id (variant_id, &variant);
     682            3 :       rust_assert (ok);
     683              :     }
     684              :   else
     685              :     {
     686           76 :       rust_assert (tyty->is_unit ());
     687              :     }
     688              : 
     689           79 :   translated = unit_expression (struct_expr.get_locus ());
     690              : }
     691              : 
     692              : void
     693         1336 : CompileExpr::visit (HIR::StructExprStructFields &struct_expr)
     694              : {
     695         1336 :   TyTy::BaseType *tyty = nullptr;
     696         1336 :   if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
     697              :                                        &tyty))
     698              :     {
     699            0 :       rust_error_at (struct_expr.get_locus (), "unknown type");
     700         1250 :       return;
     701              :     }
     702         1336 :   if (!tyty->is<TyTy::ADTType> ())
     703              :     return;
     704              : 
     705              :   // it must be an ADT
     706         1336 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
     707         1336 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
     708              : 
     709              :   // what variant is it?
     710         1336 :   int union_disriminator = struct_expr.union_index;
     711         1336 :   TyTy::VariantDef *variant = nullptr;
     712         1336 :   if (!adt->is_enum ())
     713              :     {
     714         1250 :       rust_assert (adt->number_of_variants () == 1);
     715         1250 :       variant = adt->get_variants ().at (0);
     716              :     }
     717              :   else
     718              :     {
     719           86 :       HirId variant_id;
     720           86 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
     721           86 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
     722              :         &variant_id);
     723           86 :       rust_assert (ok);
     724              : 
     725           86 :       ok
     726           86 :         = adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator);
     727           86 :       rust_assert (ok);
     728              :     }
     729              : 
     730              :   // compile it
     731         1336 :   tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
     732              : 
     733         1336 :   std::vector<tree> arguments;
     734         1336 :   if (adt->is_union ())
     735              :     {
     736          100 :       rust_assert (struct_expr.get_fields ().size () == 1);
     737              : 
     738              :       // assignments are coercion sites so lets convert the rvalue if
     739              :       // necessary
     740          100 :       auto respective_field = variant->get_field_at_index (union_disriminator);
     741          100 :       auto expected = respective_field->get_field_type ();
     742              : 
     743              :       // process arguments
     744          100 :       auto &argument = struct_expr.get_fields ().at (0);
     745          100 :       auto lvalue_locus
     746          100 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
     747          100 :       auto rvalue_locus = argument->get_locus ();
     748          100 :       auto rvalue = CompileStructExprField::Compile (*argument, ctx);
     749              : 
     750          100 :       TyTy::BaseType *actual = nullptr;
     751          100 :       bool ok = ctx->get_tyctx ()->lookup_type (
     752          100 :         argument->get_mappings ().get_hirid (), &actual);
     753              : 
     754          100 :       if (ok)
     755              :         {
     756          100 :           rvalue
     757          100 :             = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
     758              :                              actual, expected, lvalue_locus, rvalue_locus);
     759              :         }
     760              : 
     761              :       // add it to the list
     762          100 :       arguments.push_back (rvalue);
     763              :     }
     764              :   else
     765              :     {
     766              :       // this assumes all fields are in order from type resolution and if a
     767              :       // base struct was specified those fields are filed via accessors
     768         4129 :       for (size_t i = 0; i < struct_expr.get_fields ().size (); i++)
     769              :         {
     770              :           // assignments are coercion sites so lets convert the rvalue if
     771              :           // necessary
     772         2893 :           auto respective_field = variant->get_field_at_index (i);
     773         2893 :           auto expected = respective_field->get_field_type ();
     774              : 
     775              :           // process arguments
     776         2893 :           auto &argument = struct_expr.get_fields ().at (i);
     777         2893 :           auto lvalue_locus
     778         2893 :             = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
     779         2893 :           auto rvalue_locus = argument->get_locus ();
     780         2893 :           auto rvalue = CompileStructExprField::Compile (*argument, ctx);
     781              : 
     782         2893 :           TyTy::BaseType *actual = nullptr;
     783         2893 :           bool ok = ctx->get_tyctx ()->lookup_type (
     784         2893 :             argument->get_mappings ().get_hirid (), &actual);
     785              : 
     786              :           // coerce it if required/possible see
     787              :           // compile/torture/struct_base_init_1.rs
     788         2893 :           if (ok)
     789              :             {
     790         2277 :               rvalue
     791         2277 :                 = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
     792              :                                  actual, expected, lvalue_locus, rvalue_locus);
     793              :             }
     794              : 
     795              :           // add it to the list
     796         2893 :           arguments.push_back (rvalue);
     797              :         }
     798              :     }
     799              : 
     800         1336 :   if (!adt->is_enum ())
     801              :     {
     802         1250 :       auto repr_kind = adt->get_repr_options ().repr_kind;
     803         1250 :       if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
     804              :         {
     805            2 :           translated
     806            2 :             = fold_build1_loc (struct_expr.get_locus (), VIEW_CONVERT_EXPR,
     807            2 :                                compiled_adt_type, arguments.front ());
     808              :         }
     809              :       else
     810              :         {
     811         1248 :           translated
     812         1248 :             = Backend::constructor_expression (compiled_adt_type,
     813              :                                                adt->is_enum (), arguments,
     814              :                                                union_disriminator,
     815              :                                                struct_expr.get_locus ());
     816              :         }
     817              : 
     818         1250 :       return;
     819              :     }
     820              : 
     821           86 :   HIR::Expr &discrim_expr = variant->get_discriminant ();
     822           86 :   tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
     823           86 :   tree folded_discrim_expr = fold_expr (discrim_expr_node);
     824           86 :   tree qualifier = folded_discrim_expr;
     825              : 
     826           86 :   tree enum_root_files = TYPE_FIELDS (compiled_adt_type);
     827           86 :   tree payload_root = DECL_CHAIN (enum_root_files);
     828              : 
     829           86 :   tree payload = Backend::constructor_expression (TREE_TYPE (payload_root),
     830              :                                                   adt->is_enum (), arguments,
     831              :                                                   union_disriminator,
     832              :                                                   struct_expr.get_locus ());
     833              : 
     834           86 :   std::vector<tree> ctor_arguments = {qualifier, payload};
     835              : 
     836           86 :   translated
     837           86 :     = Backend::constructor_expression (compiled_adt_type, 0, ctor_arguments, -1,
     838              :                                        struct_expr.get_locus ());
     839         1336 : }
     840              : 
     841              : void
     842          383 : CompileExpr::visit (HIR::GroupedExpr &expr)
     843              : {
     844          383 :   translated = CompileExpr::Compile (expr.get_expr_in_parens (), ctx);
     845          383 : }
     846              : 
     847              : void
     848         5710 : CompileExpr::visit (HIR::FieldAccessExpr &expr)
     849              : {
     850         5710 :   HIR::Expr &receiver_expr = expr.get_receiver_expr ();
     851         5710 :   tree receiver_ref = CompileExpr::Compile (receiver_expr, ctx);
     852              : 
     853              :   // resolve the receiver back to ADT type
     854         5710 :   TyTy::BaseType *receiver = nullptr;
     855         5710 :   if (!ctx->get_tyctx ()->lookup_type (
     856         5710 :         expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver))
     857              :     {
     858            0 :       rust_error_at (expr.get_receiver_expr ().get_locus (),
     859              :                      "unresolved type for receiver");
     860           18 :       return;
     861              :     }
     862              : 
     863         5710 :   size_t field_index = 0;
     864              : 
     865         5710 :   if (auto inner_ty = TyTy::try_get_box_inner_type (receiver))
     866              :     {
     867            3 :       rust_assert ((*inner_ty)->get_kind () == TyTy::TypeKind::ADT);
     868            3 :       TyTy::ADTType *inner_adt = static_cast<TyTy::ADTType *> (*inner_ty);
     869            3 :       TyTy::VariantDef *variant = inner_adt->get_variants ().at (0);
     870              : 
     871            3 :       bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
     872              :                                        nullptr, &field_index);
     873            3 :       rust_assert (ok);
     874              : 
     875            3 :       receiver_ref = build_box_inner_ptr (receiver_ref, expr.get_locus ());
     876            3 :       receiver_ref = indirect_expression (receiver_ref, expr.get_locus ());
     877              :     }
     878         5707 :   else if (receiver->get_kind () == TyTy::TypeKind::ADT)
     879              :     {
     880         2079 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
     881         2079 :       rust_assert (!adt->is_enum ());
     882         2079 :       rust_assert (adt->number_of_variants () == 1);
     883              : 
     884         2079 :       TyTy::VariantDef *variant = adt->get_variants ().at (0);
     885         2079 :       bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
     886              :                                        nullptr, &field_index);
     887         2079 :       rust_assert (ok);
     888              : 
     889         2079 :       auto repr_kind = adt->get_repr_options ().repr_kind;
     890         2079 :       if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
     891              :         {
     892            2 :           translated
     893            2 :             = compile_transparent_field_access (variant, expr.get_locus (),
     894              :                                                 receiver_ref);
     895           18 :           return;
     896              :         }
     897              :     }
     898         3628 :   else if (receiver->get_kind () == TyTy::TypeKind::REF)
     899              :     {
     900         3628 :       TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
     901         3628 :       TyTy::BaseType *b = r->get_base ();
     902         3628 :       rust_assert (b->get_kind () == TyTy::TypeKind::ADT);
     903              : 
     904         3628 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b);
     905         3628 :       rust_assert (!adt->is_enum ());
     906         3628 :       rust_assert (adt->number_of_variants () == 1);
     907              : 
     908         3628 :       TyTy::VariantDef *variant = adt->get_variants ().at (0);
     909         3628 :       bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
     910              :                                        nullptr, &field_index);
     911         3628 :       rust_assert (ok);
     912              : 
     913         3628 :       auto repr_kind = adt->get_repr_options ().repr_kind;
     914         3628 :       if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
     915              :         {
     916           16 :           translated
     917           16 :             = compile_transparent_field_access (variant, expr.get_locus (),
     918              :                                                 receiver_ref);
     919           16 :           return;
     920              :         }
     921              :       else
     922              :         {
     923         3612 :           if (RS_DST_FLAG_P (TREE_TYPE (receiver_ref)))
     924              :             {
     925            0 :               tree data_ptr_field = TYPE_FIELDS (TREE_TYPE (receiver_ref));
     926            0 :               tree data_ptr_expr
     927            0 :                 = build3_loc (expr.get_locus (), COMPONENT_REF,
     928            0 :                               TREE_TYPE (data_ptr_field), receiver_ref,
     929              :                               data_ptr_field, NULL_TREE);
     930            0 :               receiver_ref = data_ptr_expr;
     931              :             }
     932         3612 :           tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
     933         3612 :           receiver_ref = indirect;
     934              :         }
     935              :     }
     936              : 
     937         5692 :   translated = Backend::struct_field_expression (receiver_ref, field_index,
     938              :                                                  expr.get_locus ());
     939              : }
     940              : 
     941              : void
     942          121 : CompileExpr::visit (HIR::QualifiedPathInExpression &expr)
     943              : {
     944          121 :   translated = ResolvePathRef::Compile (expr, ctx);
     945          121 : }
     946              : 
     947              : void
     948        46766 : CompileExpr::visit (HIR::PathInExpression &expr)
     949              : {
     950        46766 :   translated = ResolvePathRef::Compile (expr, ctx);
     951        46766 : }
     952              : 
     953              : void
     954          150 : CompileExpr::visit (HIR::LoopExpr &expr)
     955              : {
     956          150 :   TyTy::BaseType *block_tyty = nullptr;
     957          150 :   fncontext fnctx = ctx->peek_fn ();
     958          150 :   if (ctx->const_context_p () && !DECL_DECLARED_CONSTEXPR_P (fnctx.fndecl))
     959              :     {
     960            3 :       rich_location r (line_table, expr.get_locus ());
     961            3 :       rust_error_at (r, ErrorCode::E0658,
     962              :                      "%<loop%> is not allowed in const context");
     963            3 :       return;
     964            3 :     }
     965              : 
     966          147 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     967              :                                        &block_tyty))
     968              :     {
     969            0 :       rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
     970            0 :       return;
     971              :     }
     972              : 
     973          147 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     974          147 :   tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
     975              : 
     976          147 :   bool is_address_taken = false;
     977          147 :   tree ret_var_stmt = NULL_TREE;
     978          147 :   Bvariable *tmp
     979          147 :     = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     980              :                                    NULL, is_address_taken, expr.get_locus (),
     981              :                                    &ret_var_stmt);
     982          147 :   ctx->add_statement (ret_var_stmt);
     983          147 :   ctx->push_loop_context (tmp);
     984              : 
     985          147 :   tl::optional<HIR::LoopLabel> loop_label = tl::nullopt;
     986          147 :   if (expr.has_loop_label ())
     987              :     {
     988           44 :       loop_label = expr.get_loop_label ();
     989           44 :       ctx->insert_var_decl (
     990           88 :         loop_label.value ().get_lifetime ().get_mappings ().get_hirid (), tmp);
     991              :     }
     992          147 :   std::pair<tree, tree> loop_labels = construct_loop_labels (loop_label);
     993          147 :   tree loop_begin_label = loop_labels.first;
     994          147 :   tree loop_end_label = loop_labels.second;
     995              : 
     996              :   // label before the loop - continue should goto here
     997          147 :   ctx->add_statement (loop_begin_label);
     998              : 
     999              :   // loop body
    1000          147 :   tree code_block
    1001          147 :     = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr);
    1002          147 :   tree loop_expr = Backend::loop_expression (code_block, expr.get_locus ());
    1003          147 :   ctx->add_statement (loop_expr);
    1004              : 
    1005          147 :   ctx->pop_loop_context ();
    1006          147 :   translated = Backend::var_expression (tmp, expr.get_locus ());
    1007              : 
    1008              :   // label after the loop - break should goto here
    1009          147 :   ctx->add_statement (loop_end_label);
    1010              : 
    1011              :   // in construct_loop fn we push these labels
    1012          147 :   ctx->pop_loop_begin_label ();
    1013          147 :   ctx->pop_loop_end_label ();
    1014          147 : }
    1015              : 
    1016              : void
    1017           97 : CompileExpr::visit (HIR::WhileLoopExpr &expr)
    1018              : {
    1019           97 :   fncontext fnctx = ctx->peek_fn ();
    1020           97 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
    1021           97 :   ctx->push_loop_context (nullptr);
    1022           97 :   tl::optional<HIR::LoopLabel> loop_label = tl::nullopt;
    1023           97 :   if (expr.has_loop_label ())
    1024           14 :     loop_label = tl::optional<HIR::LoopLabel> (expr.get_loop_label ());
    1025           97 :   std::pair<tree, tree> loop_labels = construct_loop_labels (loop_label);
    1026           97 :   tree loop_begin_label = loop_labels.first;
    1027           97 :   tree loop_end_label = loop_labels.second;
    1028           97 :   std::vector<Bvariable *> locals;
    1029           97 :   location_t start_location = expr.get_loop_block ().get_locus ();
    1030           97 :   location_t end_location = expr.get_loop_block ().get_locus (); // FIXME
    1031              : 
    1032           97 :   tree loop_block = Backend::block (fnctx.fndecl, enclosing_scope, locals,
    1033              :                                     start_location, end_location);
    1034           97 :   ctx->push_block (loop_block);
    1035           97 :   ctx->add_statement (loop_begin_label);
    1036              : 
    1037           97 :   HIR::Expr &predicate = expr.get_predicate_expr ();
    1038           97 :   TyTy::BaseType *predicate_type = nullptr;
    1039           97 :   bool ok
    1040           97 :     = ctx->get_tyctx ()->lookup_type (predicate.get_mappings ().get_hirid (),
    1041              :                                       &predicate_type);
    1042           97 :   rust_assert (ok && predicate_type != nullptr);
    1043           97 :   tree condition = CompileExpr::Compile (predicate, ctx);
    1044           97 :   if (predicate_type->get_kind () == TyTy::TypeKind::NEVER)
    1045              :     {
    1046            9 :       ctx->add_statement (condition);
    1047            9 :       condition = boolean_true_node;
    1048              :     }
    1049           97 :   tree exit_condition = fold_build1_loc (expr.get_locus (), TRUTH_NOT_EXPR,
    1050              :                                          boolean_type_node, condition);
    1051           97 :   tree exit_expr = Backend::exit_expression (exit_condition, expr.get_locus ());
    1052           97 :   ctx->add_statement (exit_expr);
    1053              : 
    1054           97 :   tree code_block_stmt
    1055           97 :     = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr);
    1056           97 :   rust_assert (TREE_CODE (code_block_stmt) == BIND_EXPR);
    1057           97 :   ctx->add_statement (code_block_stmt);
    1058              : 
    1059           97 :   ctx->pop_loop_begin_label ();
    1060           97 :   ctx->pop_block ();
    1061              : 
    1062           97 :   tree loop_expr = Backend::loop_expression (loop_block, expr.get_locus ());
    1063           97 :   ctx->add_statement (loop_expr);
    1064           97 :   ctx->add_statement (loop_end_label);
    1065           97 :   ctx->pop_loop_end_label ();
    1066              : 
    1067           97 :   translated = unit_expression (expr.get_locus ());
    1068           97 : }
    1069              : 
    1070              : void
    1071          114 : CompileExpr::visit (HIR::BreakExpr &expr)
    1072              : {
    1073          114 :   if (expr.has_break_expr () && expr.has_label ())
    1074              :     {
    1075            5 :       HIR::Lifetime &label = expr.get_label ();
    1076            5 :       auto tvar = lookup_label_temp_var (label.get_mappings ().get_nodeid ());
    1077            5 :       tree value = CompileExpr::Compile (expr.get_expr (), ctx);
    1078            5 :       tree assign
    1079            5 :         = Backend::assignment_statement (tvar->get_tree (label.get_locus ()),
    1080              :                                          value, label.get_locus ());
    1081            5 :       HirId label_hirid = resolve_nodeid (label.get_mappings ().get_nodeid (),
    1082              :                                           Resolver2_0::Namespace::Labels);
    1083            5 :       tl::optional<tree> block_label = ctx->lookup_break_label (label_hirid);
    1084            5 :       rust_assert (block_label.has_value ());
    1085            5 :       tree go_to
    1086            5 :         = Backend::goto_statement (block_label.value (), label.get_locus ());
    1087            5 :       ctx->add_statement (assign);
    1088            5 :       ctx->add_statement (go_to);
    1089            5 :       return;
    1090              :     }
    1091          109 :   if (expr.has_break_expr ())
    1092              :     {
    1093           17 :       tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx);
    1094           17 :       translated = error_mark_node;
    1095              : 
    1096           17 :       if (!ctx->have_loop_context ())
    1097              :         return;
    1098              : 
    1099           17 :       Bvariable *loop_result_holder = ctx->peek_loop_context ();
    1100           17 :       if (loop_result_holder == nullptr)
    1101              :         return;
    1102              : 
    1103           16 :       tree result_reference
    1104           16 :         = Backend::var_expression (loop_result_holder,
    1105           16 :                                    expr.get_expr ().get_locus ());
    1106              : 
    1107           16 :       tree assignment
    1108           16 :         = Backend::assignment_statement (result_reference, compiled_expr,
    1109              :                                          expr.get_locus ());
    1110           16 :       ctx->add_statement (assignment);
    1111              :     }
    1112              : 
    1113          108 :   if (expr.has_label ())
    1114              :     {
    1115           28 :       auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    1116              : 
    1117           28 :       NodeId resolved_node_id;
    1118           28 :       if (auto id
    1119           28 :           = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid (),
    1120           28 :                            Resolver2_0::Namespace::Labels))
    1121              :         {
    1122           28 :           resolved_node_id = *id;
    1123              :         }
    1124              :       else
    1125              :         {
    1126            0 :           rust_error_at (
    1127            0 :             expr.get_label ().get_locus (),
    1128              :             "failed to resolve compiled label for label %s",
    1129            0 :             expr.get_label ().get_mappings ().as_string ().c_str ());
    1130            0 :           return;
    1131              :         }
    1132           28 :       tl::optional<HirId> hid
    1133           28 :         = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
    1134           28 :       if (!hid.has_value ())
    1135              :         {
    1136            0 :           rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
    1137              :           return;
    1138              :         }
    1139           28 :       auto ref = hid.value ();
    1140              : 
    1141           28 :       tl::optional<tree> label = ctx->lookup_break_label (ref);
    1142           28 :       rust_assert (label.has_value ());
    1143           28 :       tree goto_label
    1144           28 :         = Backend::goto_statement (label.value (), expr.get_locus ());
    1145           28 :       ctx->add_statement (goto_label);
    1146              :     }
    1147              :   else
    1148              :     {
    1149           80 :       translated
    1150           80 :         = Backend::exit_expression (Backend::boolean_constant_expression (true),
    1151              :                                     expr.get_locus ());
    1152              :     }
    1153              : }
    1154              : 
    1155              : void
    1156           25 : CompileExpr::visit (HIR::ContinueExpr &expr)
    1157              : {
    1158           25 :   translated = error_mark_node;
    1159           25 :   rust_assert (ctx->have_loop_context () && "continue is outside of loop");
    1160              : 
    1161           25 :   tree label = ctx->peek_loop_begin_label ();
    1162           25 :   if (expr.has_label ())
    1163              :     {
    1164            6 :       auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    1165              : 
    1166            6 :       NodeId resolved_node_id;
    1167            6 :       if (auto id
    1168            6 :           = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid (),
    1169            6 :                            Resolver2_0::Namespace::Labels))
    1170              :         {
    1171            6 :           resolved_node_id = *id;
    1172              :         }
    1173              :       else
    1174              :         {
    1175            0 :           rust_error_at (
    1176            0 :             expr.get_label ().get_locus (),
    1177              :             "failed to resolve compiled label for label %s",
    1178            0 :             expr.get_label ().get_mappings ().as_string ().c_str ());
    1179            0 :           return;
    1180              :         }
    1181              : 
    1182            6 :       tl::optional<HirId> hid
    1183            6 :         = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
    1184            6 :       if (!hid.has_value ())
    1185              :         {
    1186            0 :           rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
    1187              :           return;
    1188              :         }
    1189            6 :       auto ref = hid.value ();
    1190            6 :       tl::optional<tree> opt_label = ctx->lookup_continue_label (ref);
    1191            6 :       rust_assert (opt_label.has_value ());
    1192            6 :       label = opt_label.value ();
    1193              :     }
    1194              : 
    1195           25 :   translated = Backend::goto_statement (label, expr.get_locus ());
    1196              : }
    1197              : 
    1198              : void
    1199         2007 : CompileExpr::visit (HIR::BorrowExpr &expr)
    1200              : {
    1201         2007 :   tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx);
    1202         2007 :   if (RS_DST_FLAG_P (TREE_TYPE (main_expr)))
    1203              :     {
    1204           93 :       translated = main_expr;
    1205           93 :       return;
    1206              :     }
    1207              : 
    1208              :   // const expr needs these to be addressable temps otherwise it cant cope. We
    1209              :   // get away with this during regular compilation because gcc middle end
    1210              :   // optimizes it
    1211         1914 :   if (TREE_CODE (main_expr) == CONSTRUCTOR && !TREE_CONSTANT (main_expr))
    1212              :     {
    1213            2 :       tree init_stmt = NULL_TREE;
    1214            2 :       Bvariable *tmp
    1215            4 :         = Backend::temporary_variable (ctx->peek_fn ().fndecl,
    1216            2 :                                        ctx->peek_enclosing_scope (),
    1217            2 :                                        TREE_TYPE (main_expr), main_expr, true,
    1218              :                                        expr.get_locus (), &init_stmt);
    1219            2 :       ctx->add_statement (init_stmt);
    1220            2 :       main_expr = Backend::var_expression (tmp, expr.get_locus ());
    1221              :     }
    1222              : 
    1223         1914 :   TyTy::BaseType *tyty = nullptr;
    1224         1914 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1225              :                                        &tyty))
    1226              :     return;
    1227              : 
    1228         1914 :   tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
    1229              : 
    1230         1914 :   bool is_fat_ptr
    1231         1914 :     = tyty->is<TyTy::ReferenceType> ()
    1232         1914 :         ? tyty->as<TyTy::ReferenceType> ()->get_base ()->is_unsized ()
    1233            4 :       : tyty->is<TyTy::PointerType> ()
    1234            4 :         ? tyty->as<TyTy::PointerType> ()->get_base ()->is_unsized ()
    1235         1914 :         : false;
    1236              : 
    1237         1914 :   if (is_fat_ptr)
    1238              :     {
    1239            0 :       tree data_ptr
    1240            0 :         = address_expression (main_expr, expr.get_locus (), NULL_TREE);
    1241            0 :       tree meta = error_mark_node;
    1242            0 :       if (TREE_CODE (main_expr) == COMPONENT_REF)
    1243              :         {
    1244            0 :           tree indirect = TREE_OPERAND (main_expr, 0);
    1245            0 :           if (TREE_CODE (indirect) == INDIRECT_REF)
    1246              :             {
    1247            0 :               tree data_ptr_expr = TREE_OPERAND (indirect, 0);
    1248            0 :               if (TREE_CODE (data_ptr_expr) == COMPONENT_REF)
    1249              :                 {
    1250            0 :                   tree fat_ptr = TREE_OPERAND (data_ptr_expr, 0);
    1251            0 :                   if (RS_DST_FLAG_P (TREE_TYPE (fat_ptr)))
    1252              :                     {
    1253            0 :                       tree meta_field
    1254            0 :                         = DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (fat_ptr)));
    1255            0 :                       meta = build3_loc (expr.get_locus (), COMPONENT_REF,
    1256            0 :                                          TREE_TYPE (meta_field), fat_ptr,
    1257              :                                          meta_field, NULL_TREE);
    1258              :                     }
    1259              :                 }
    1260              :             }
    1261              :         }
    1262            0 :       if (meta != error_mark_node)
    1263              :         {
    1264            0 :           std::vector<tree> constructor_elements = {data_ptr, meta};
    1265            0 :           translated = Backend::constructor_expression (expected_type, false,
    1266              :                                                         constructor_elements,
    1267              :                                                         -1, expr.get_locus ());
    1268            0 :           return;
    1269            0 :         }
    1270              :     }
    1271              : 
    1272         1914 :   translated = address_expression (main_expr, expr.get_locus (), expected_type);
    1273              : }
    1274              : 
    1275              : void
    1276         3995 : CompileExpr::visit (HIR::DereferenceExpr &expr)
    1277              : {
    1278         3995 :   TyTy::BaseType *tyty = nullptr;
    1279         3995 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1280              :                                        &tyty))
    1281              :     {
    1282            0 :       rust_fatal_error (expr.get_locus (),
    1283              :                         "did not resolve type for this TupleExpr");
    1284           35 :       return;
    1285              :     }
    1286              : 
    1287         3995 :   tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx);
    1288              : 
    1289              :   // Box<T> Dereference Hook
    1290              :   // Typechecker treats 'Box<T>' as a privileged pointer and allows
    1291              :   // explicit dereferencing.However, the backend sees Box as a normal
    1292              :   // RECORD_TYPE (struct). To solve this, if the type is the 'owned_box'
    1293              :   // lang item, we drill down.
    1294         3995 :   TyTy::BaseType *base_tyty;
    1295         3995 :   if (ctx->get_tyctx ()->lookup_type (
    1296         3995 :         expr.get_expr ().get_mappings ().get_hirid (), &base_tyty))
    1297              :     {
    1298         3995 :       if (TyTy::try_get_box_inner_type (base_tyty))
    1299              :         {
    1300            1 :           main_expr = build_box_inner_ptr (main_expr, expr.get_locus ());
    1301              :         }
    1302              :     }
    1303              : 
    1304              :   // this might be an operator overload situation lets check
    1305         3995 :   TyTy::FnType *fntype;
    1306         3995 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    1307         3995 :     expr.get_mappings ().get_hirid (), &fntype);
    1308         3995 :   if (is_op_overload)
    1309              :     {
    1310           49 :       auto lang_item_type = LangItem::Kind::DEREF;
    1311           49 :       tree operator_overload_call
    1312           49 :         = resolve_operator_overload (lang_item_type, expr, main_expr, nullptr,
    1313              :                                      expr.get_expr (), tl::nullopt);
    1314              : 
    1315              :       // rust deref always returns a reference from this overload then we can
    1316              :       // actually do the indirection
    1317           49 :       main_expr = operator_overload_call;
    1318              :     }
    1319              : 
    1320         3995 :   tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
    1321         3995 :   if (RS_DST_FLAG_P (TREE_TYPE (main_expr)) && RS_DST_FLAG_P (expected_type))
    1322              :     {
    1323           35 :       translated = main_expr;
    1324           35 :       return;
    1325              :     }
    1326              : 
    1327         3960 :   translated = indirect_expression (main_expr, expr.get_locus ());
    1328              : }
    1329              : 
    1330              : void
    1331        24927 : CompileExpr::visit (HIR::LiteralExpr &expr)
    1332              : {
    1333        24927 :   TyTy::BaseType *tyty = nullptr;
    1334        24927 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1335              :                                        &tyty))
    1336        24927 :     return;
    1337              : 
    1338        24927 :   switch (expr.get_lit_type ())
    1339              :     {
    1340          928 :     case HIR::Literal::BOOL:
    1341          928 :       translated = compile_bool_literal (expr, tyty);
    1342          928 :       return;
    1343              : 
    1344        19981 :     case HIR::Literal::INT:
    1345        19981 :       translated = compile_integer_literal (expr, tyty);
    1346        19981 :       return;
    1347              : 
    1348          999 :     case HIR::Literal::FLOAT:
    1349          999 :       translated = compile_float_literal (expr, tyty);
    1350          999 :       return;
    1351              : 
    1352          183 :     case HIR::Literal::CHAR:
    1353          183 :       translated = compile_char_literal (expr, tyty);
    1354          183 :       return;
    1355              : 
    1356          408 :     case HIR::Literal::BYTE:
    1357          408 :       translated = compile_byte_literal (expr, tyty);
    1358          408 :       return;
    1359              : 
    1360         2379 :     case HIR::Literal::STRING:
    1361         2379 :       translated = compile_string_literal (expr, tyty);
    1362         2379 :       return;
    1363              : 
    1364           35 :     case HIR::Literal::BYTE_STRING:
    1365           35 :       translated = compile_byte_string_literal (expr, tyty);
    1366           35 :       return;
    1367              : 
    1368           14 :     case HIR::Literal::C_STRING:
    1369           14 :       translated = compile_c_string_literal (expr, tyty);
    1370           14 :       return;
    1371              :     }
    1372              : }
    1373              : 
    1374              : void
    1375         2470 : CompileExpr::visit (HIR::AssignmentExpr &expr)
    1376              : {
    1377         2470 :   auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx);
    1378         2470 :   auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx);
    1379              : 
    1380              :   // assignments are coercion sites so lets convert the rvalue if necessary
    1381         2470 :   TyTy::BaseType *expected = nullptr;
    1382         2470 :   TyTy::BaseType *actual = nullptr;
    1383              : 
    1384         2470 :   bool ok;
    1385         2470 :   ok = ctx->get_tyctx ()->lookup_type (
    1386         2470 :     expr.get_lhs ().get_mappings ().get_hirid (), &expected);
    1387         2470 :   rust_assert (ok);
    1388              : 
    1389         2470 :   ok = ctx->get_tyctx ()->lookup_type (
    1390         2470 :     expr.get_rhs ().get_mappings ().get_hirid (), &actual);
    1391         2470 :   rust_assert (ok);
    1392              : 
    1393         2470 :   rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual,
    1394         2470 :                           expected, expr.get_lhs ().get_locus (),
    1395         2470 :                           expr.get_rhs ().get_locus ());
    1396              : 
    1397              :   // rust_debug_loc (expr.get_locus (), "XXXXXX assignment");
    1398              :   // debug_tree (rvalue);
    1399              :   // debug_tree (lvalue);
    1400              : 
    1401         2470 :   tree assignment
    1402         2470 :     = Backend::assignment_statement (lvalue, rvalue, expr.get_locus ());
    1403              : 
    1404         2470 :   ctx->add_statement (assignment);
    1405         2470 :   translated = unit_expression (expr.get_locus ());
    1406         2470 : }
    1407              : 
    1408              : // Helper for CompileExpr::visit (HIR::MatchExpr).
    1409              : // Check that the scrutinee of EXPR is a valid kind of expression to match on.
    1410              : // Return the TypeKind of the scrutinee if it is valid, or TyTy::TypeKind::ERROR
    1411              : // if not.
    1412              : static TyTy::TypeKind
    1413          907 : check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx)
    1414              : {
    1415          907 :   TyTy::BaseType *scrutinee_expr_tyty = nullptr;
    1416          907 :   if (!ctx->get_tyctx ()->lookup_type (
    1417          907 :         expr.get_scrutinee_expr ().get_mappings ().get_hirid (),
    1418              :         &scrutinee_expr_tyty))
    1419              :     {
    1420              :       return TyTy::TypeKind::ERROR;
    1421              :     }
    1422              : 
    1423          907 :   TyTy::TypeKind scrutinee_kind = scrutinee_expr_tyty->get_kind ();
    1424              : 
    1425          907 :   if (scrutinee_kind == TyTy::TypeKind::FLOAT)
    1426              :     {
    1427              :       // FIXME: CASE_LABEL_EXPR does not support floating point types.
    1428              :       // Find another way to compile these.
    1429            2 :       rust_sorry_at (expr.get_locus (),
    1430              :                      "match on floating-point types is not yet supported");
    1431              :     }
    1432              : 
    1433          907 :   TyTy::BaseType *expr_tyty = nullptr;
    1434          907 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1435              :                                        &expr_tyty))
    1436              :     {
    1437            0 :       return TyTy::TypeKind::ERROR;
    1438              :     }
    1439              : 
    1440              :   return scrutinee_kind;
    1441              : }
    1442              : 
    1443              : void
    1444          907 : CompileExpr::visit (HIR::MatchExpr &expr)
    1445              : {
    1446              :   // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
    1447              :   // TODO
    1448              :   // SWITCH_ALL_CASES_P is true if the switch includes a default label or the
    1449              :   // case label ranges cover all possible values of the condition expression
    1450              : 
    1451          907 :   TyTy::TypeKind scrutinee_kind = check_match_scrutinee (expr, ctx);
    1452          907 :   if (scrutinee_kind == TyTy::TypeKind::ERROR)
    1453              :     {
    1454            0 :       translated = error_mark_node;
    1455            4 :       return;
    1456              :     }
    1457              : 
    1458          907 :   TyTy::BaseType *expr_tyty = nullptr;
    1459          907 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1460              :                                        &expr_tyty))
    1461              :     {
    1462            0 :       translated = error_mark_node;
    1463            0 :       return;
    1464              :     }
    1465              : 
    1466              :   // if the result of this expression is meant to be never type then we can
    1467              :   // optimise this away but there is the case where match arms resolve to !
    1468              :   // because of return statements we need to special case this
    1469          907 :   if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ())
    1470              :     {
    1471            4 :       translated = unit_expression (expr.get_locus ());
    1472            4 :       return;
    1473              :     }
    1474              : 
    1475          903 :   fncontext fnctx = ctx->peek_fn ();
    1476          903 :   Bvariable *tmp = NULL;
    1477          903 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
    1478          903 :   tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
    1479              : 
    1480          903 :   bool is_address_taken = false;
    1481          903 :   tree ret_var_stmt = nullptr;
    1482          903 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
    1483              :                                      NULL, is_address_taken, expr.get_locus (),
    1484              :                                      &ret_var_stmt);
    1485          903 :   ctx->add_statement (ret_var_stmt);
    1486              : 
    1487              :   // lets compile the scrutinee expression
    1488          903 :   tree match_scrutinee_rval
    1489          903 :     = CompileExpr::Compile (expr.get_scrutinee_expr (), ctx);
    1490              : 
    1491          903 :   Bvariable *match_scrutinee_tmp_var
    1492          903 :     = Backend::temporary_variable (fnctx.fndecl, enclosing_scope,
    1493          903 :                                    TREE_TYPE (match_scrutinee_rval), NULL,
    1494              :                                    is_address_taken, expr.get_locus (),
    1495              :                                    &ret_var_stmt);
    1496          903 :   ctx->add_statement (ret_var_stmt);
    1497              : 
    1498          903 :   tree match_scrutinee_expr = match_scrutinee_tmp_var->get_tree (
    1499          903 :     expr.get_scrutinee_expr ().get_locus ());
    1500              : 
    1501          903 :   tree assignment
    1502          903 :     = Backend::assignment_statement (match_scrutinee_expr, match_scrutinee_rval,
    1503              :                                      expr.get_locus ());
    1504          903 :   ctx->add_statement (assignment);
    1505              : 
    1506              :   // setup the end label so the cases can exit properly
    1507          903 :   tree fndecl = fnctx.fndecl;
    1508          903 :   location_t end_label_locus = expr.get_locus (); // FIXME
    1509              :   // tl::nullopt creates an artificial label
    1510          903 :   tree end_label = Backend::label (fndecl, tl::nullopt, end_label_locus);
    1511          903 :   tree end_label_decl_statement
    1512          903 :     = Backend::label_definition_statement (end_label);
    1513              : 
    1514         3037 :   for (auto &kase : expr.get_match_cases ())
    1515              :     {
    1516              :       // for now lets just get single pattern's working
    1517         2134 :       HIR::MatchArm &kase_arm = kase.get_arm ();
    1518         2134 :       rust_assert (kase_arm.get_pattern () != nullptr);
    1519              : 
    1520         2134 :       auto &kase_pattern = kase_arm.get_pattern ();
    1521              :       // setup the match-arm-body-block
    1522         2134 :       location_t start_location = UNKNOWN_LOCATION; // FIXME
    1523         2134 :       location_t end_location = UNKNOWN_LOCATION;   // FIXME
    1524         2134 :       tree arm_body_block = Backend::block (fndecl, enclosing_scope, {},
    1525              :                                             start_location, end_location);
    1526              : 
    1527         2134 :       ctx->push_block (arm_body_block);
    1528              : 
    1529              :       // setup the bindings for the block
    1530         2134 :       CompilePatternBindings::Compile (*kase_pattern, match_scrutinee_expr,
    1531              :                                        ctx);
    1532              : 
    1533              :       // compile the expr and setup the assignment if required when tmp !=
    1534              :       // NULL
    1535         2134 :       location_t arm_locus = kase_arm.get_locus ();
    1536         2134 :       tree kase_expr_tree = CompileExpr::Compile (kase.get_expr (), ctx);
    1537         2134 :       tree result_reference = Backend::var_expression (tmp, arm_locus);
    1538              : 
    1539         2134 :       TyTy::BaseType *actual = nullptr;
    1540         2134 :       bool ok = ctx->get_tyctx ()->lookup_type (
    1541         2134 :         kase.get_expr ().get_mappings ().get_hirid (), &actual);
    1542         2134 :       rust_assert (ok);
    1543              : 
    1544         2134 :       tree coerced_result
    1545         2134 :         = coercion_site (kase.get_expr ().get_mappings ().get_hirid (),
    1546              :                          kase_expr_tree, actual, expr_tyty, expr.get_locus (),
    1547              :                          arm_locus);
    1548              : 
    1549         2134 :       tree assignment
    1550         2134 :         = Backend::assignment_statement (result_reference, coerced_result,
    1551              :                                          arm_locus);
    1552         2134 :       ctx->add_statement (assignment);
    1553              : 
    1554              :       // go to end label
    1555         2134 :       tree goto_end_label
    1556         2134 :         = build1_loc (arm_locus, GOTO_EXPR, void_type_node, end_label);
    1557         2134 :       ctx->add_statement (goto_end_label);
    1558              : 
    1559         2134 :       ctx->pop_block ();
    1560              : 
    1561         2134 :       tree check_expr
    1562         2134 :         = CompilePatternCheckExpr::Compile (*kase_pattern, match_scrutinee_expr,
    1563              :                                             ctx);
    1564              : 
    1565         2134 :       tree check_stmt
    1566         2134 :         = Backend::if_statement (NULL_TREE, check_expr, arm_body_block,
    1567         2134 :                                  NULL_TREE, kase_pattern->get_locus ());
    1568              : 
    1569         2134 :       ctx->add_statement (check_stmt);
    1570              :     }
    1571              : 
    1572              :   // setup the switch expression
    1573          903 :   ctx->add_statement (end_label_decl_statement);
    1574              : 
    1575          903 :   translated = Backend::var_expression (tmp, expr.get_locus ());
    1576              : }
    1577              : 
    1578              : void
    1579        13242 : CompileExpr::visit (HIR::CallExpr &expr)
    1580              : {
    1581        13242 :   TyTy::BaseType *tyty = nullptr;
    1582        13242 :   if (!ctx->get_tyctx ()->lookup_type (
    1583        13242 :         expr.get_fnexpr ().get_mappings ().get_hirid (), &tyty))
    1584              :     {
    1585            0 :       rust_error_at (expr.get_locus (), "unknown type");
    1586         1883 :       return;
    1587              :     }
    1588              : 
    1589              :   // must be a tuple constructor
    1590        13242 :   bool is_adt_ctor = tyty->get_kind () == TyTy::TypeKind::ADT;
    1591        13242 :   if (is_adt_ctor)
    1592              :     {
    1593         1821 :       rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
    1594         1821 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
    1595         1821 :       tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
    1596              : 
    1597              :       // what variant is it?
    1598         1821 :       int union_disriminator = -1;
    1599         1821 :       TyTy::VariantDef *variant = nullptr;
    1600         1821 :       if (!adt->is_enum ())
    1601              :         {
    1602          934 :           rust_assert (adt->number_of_variants () == 1);
    1603          934 :           variant = adt->get_variants ().at (0);
    1604              :         }
    1605              :       else
    1606              :         {
    1607          887 :           HirId variant_id;
    1608          887 :           bool ok = ctx->get_tyctx ()->lookup_variant_definition (
    1609          887 :             expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id);
    1610          887 :           rust_assert (ok);
    1611              : 
    1612          887 :           ok = adt->lookup_variant_by_id (variant_id, &variant,
    1613              :                                           &union_disriminator);
    1614          887 :           rust_assert (ok);
    1615              :         }
    1616              : 
    1617              :       // this assumes all fields are in order from type resolution and if a
    1618              :       // base struct was specified those fields are filed via accessors
    1619         1821 :       std::vector<tree> arguments;
    1620         4190 :       for (size_t i = 0; i < expr.num_params (); i++)
    1621              :         {
    1622         2369 :           auto &argument = expr.get_arguments ().at (i);
    1623         2369 :           auto rvalue = CompileExpr::Compile (*argument, ctx);
    1624              : 
    1625              :           // assignments are coercion sites so lets convert the rvalue if
    1626              :           // necessary
    1627         2369 :           auto respective_field = variant->get_field_at_index (i);
    1628         2369 :           auto expected = respective_field->get_field_type ();
    1629              : 
    1630         2369 :           TyTy::BaseType *actual = nullptr;
    1631         2369 :           bool ok = ctx->get_tyctx ()->lookup_type (
    1632         2369 :             argument->get_mappings ().get_hirid (), &actual);
    1633         2369 :           rust_assert (ok);
    1634              : 
    1635              :           // coerce it if required
    1636         2369 :           location_t lvalue_locus
    1637         2369 :             = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1638         2369 :           location_t rvalue_locus = argument->get_locus ();
    1639         2369 :           rvalue
    1640         2369 :             = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1641              :                              actual, expected, lvalue_locus, rvalue_locus);
    1642              : 
    1643              :           // add it to the list
    1644         2369 :           arguments.push_back (rvalue);
    1645              :         }
    1646              : 
    1647         1821 :       if (!adt->is_enum ())
    1648              :         {
    1649          934 :           translated
    1650          934 :             = Backend::constructor_expression (compiled_adt_type,
    1651              :                                                adt->is_enum (), arguments,
    1652              :                                                union_disriminator,
    1653              :                                                expr.get_locus ());
    1654          934 :           return;
    1655              :         }
    1656              : 
    1657          887 :       HIR::Expr &discrim_expr = variant->get_discriminant ();
    1658          887 :       tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
    1659          887 :       tree folded_discrim_expr = fold_expr (discrim_expr_node);
    1660          887 :       tree qualifier = folded_discrim_expr;
    1661              : 
    1662          887 :       tree enum_root_files = TYPE_FIELDS (compiled_adt_type);
    1663          887 :       tree payload_root = DECL_CHAIN (enum_root_files);
    1664              : 
    1665          887 :       tree payload
    1666          887 :         = Backend::constructor_expression (TREE_TYPE (payload_root), true,
    1667              :                                            {arguments}, union_disriminator,
    1668              :                                            expr.get_locus ());
    1669              : 
    1670          887 :       std::vector<tree> ctor_arguments = {qualifier, payload};
    1671          887 :       translated = Backend::constructor_expression (compiled_adt_type, false,
    1672              :                                                     ctor_arguments, -1,
    1673              :                                                     expr.get_locus ());
    1674              : 
    1675          887 :       return;
    1676         2708 :     }
    1677              : 
    1678        11421 :   auto get_parameter_tyty_at_index
    1679        11543 :     = [] (const TyTy::BaseType *base, size_t index,
    1680              :           TyTy::BaseType **result) -> bool {
    1681        11543 :     bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
    1682        11543 :                  || base->get_kind () == TyTy::TypeKind::FNPTR;
    1683            0 :     rust_assert (is_fn);
    1684              : 
    1685        11543 :     if (base->get_kind () == TyTy::TypeKind::FNPTR)
    1686              :       {
    1687           28 :         const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
    1688           28 :         *result = fn->get_param_type_at (index);
    1689              : 
    1690           28 :         return true;
    1691              :       }
    1692              : 
    1693        11515 :     const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
    1694        11515 :     auto &param = fn->param_at (index);
    1695        11515 :     *result = param.get_type ();
    1696              : 
    1697        11515 :     return true;
    1698              :   };
    1699              : 
    1700              :   // special check for platform-intrinsic functions
    1701        11421 :   TyTy::FnType *platform_intrinsic = nullptr;
    1702        11421 :   if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
    1703              :     {
    1704        11332 :       auto *fn_ty = static_cast<TyTy::FnType *> (tyty);
    1705        11332 :       if (fn_ty->get_abi () == ABI::PLATFORM_INTRINSIC)
    1706        11421 :         platform_intrinsic = fn_ty;
    1707              :     }
    1708              : 
    1709        11421 :   if (ctx->const_context_p () && platform_intrinsic != nullptr)
    1710              :     {
    1711            0 :       rust_sorry_at (
    1712              :         expr.get_locus (),
    1713              :         "platform intrinsic calls in consts are not supported yet");
    1714            0 :       return;
    1715              :     }
    1716              : 
    1717        11421 :   auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
    1718        11421 :   if (ctx->const_context_p ())
    1719              :     {
    1720         1068 :       if (!FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn_address)))
    1721              :         {
    1722            1 :           rust_error_at (expr.get_locus (),
    1723              :                          "calls in constants are limited to constant "
    1724              :                          "functions, tuple structs and tuple variants");
    1725            1 :           return;
    1726              :         }
    1727              : 
    1728         1067 :       if (TREE_CODE (fn_address) == ADDR_EXPR)
    1729              :         {
    1730         1067 :           tree fndecl = TREE_OPERAND (fn_address, 0);
    1731         1067 :           if (!DECL_DECLARED_CONSTEXPR_P (fndecl))
    1732              :             {
    1733            1 :               rust_error_at (expr.get_locus (),
    1734              :                              "calls in constants are limited to constant "
    1735              :                              "functions, tuple structs and tuple variants");
    1736            1 :               return;
    1737              :             }
    1738              :         }
    1739              :     }
    1740              : 
    1741              :   // is this a closure call?
    1742        11419 :   bool possible_trait_call
    1743        11419 :     = generate_possible_fn_trait_call (expr, fn_address, &translated);
    1744        11419 :   if (possible_trait_call)
    1745              :     return;
    1746              : 
    1747        11359 :   bool is_variadic = false;
    1748        11359 :   size_t required_num_args = expr.get_arguments ().size ();
    1749              : 
    1750        11359 :   if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
    1751              :     {
    1752        11331 :       const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
    1753        11331 :       required_num_args = fn->num_params ();
    1754        11331 :       is_variadic = fn->is_variadic ();
    1755              :     }
    1756           28 :   else if (tyty->get_kind () == TyTy::TypeKind::FNPTR)
    1757              :     {
    1758           28 :       const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
    1759           28 :       required_num_args = fn->num_params ();
    1760              :     }
    1761              : 
    1762        11359 :   std::vector<tree> args;
    1763        23689 :   for (size_t i = 0; i < expr.get_arguments ().size (); i++)
    1764              :     {
    1765        12330 :       auto &argument = expr.get_arguments ().at (i);
    1766        12330 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    1767              : 
    1768        12330 :       if (is_variadic && i >= required_num_args)
    1769              :         {
    1770          787 :           args.push_back (rvalue);
    1771          787 :           continue;
    1772              :         }
    1773              : 
    1774              :       // assignments are coercion sites so lets convert the rvalue if
    1775              :       // necessary
    1776        11543 :       bool ok;
    1777        11543 :       TyTy::BaseType *expected = nullptr;
    1778        11543 :       ok = get_parameter_tyty_at_index (tyty, i, &expected);
    1779        11543 :       rust_assert (ok);
    1780              : 
    1781        11543 :       TyTy::BaseType *actual = nullptr;
    1782        11543 :       ok = ctx->get_tyctx ()->lookup_type (
    1783        11543 :         argument->get_mappings ().get_hirid (), &actual);
    1784        11543 :       rust_assert (ok);
    1785              : 
    1786              :       // coerce it if required
    1787        11543 :       location_t lvalue_locus
    1788        11543 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1789        11543 :       location_t rvalue_locus = argument->get_locus ();
    1790        11543 :       rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1791              :                               actual, expected, lvalue_locus, rvalue_locus);
    1792              : 
    1793              :       // add it to the list
    1794        11543 :       args.push_back (rvalue);
    1795              :     }
    1796              : 
    1797        11359 :   if (platform_intrinsic != nullptr)
    1798              :     {
    1799            0 :       translated = PlatformIntrinsic::compile_call (ctx, platform_intrinsic,
    1800              :                                                     args, expr.get_locus ());
    1801            0 :       return;
    1802              :     }
    1803              : 
    1804              :   // must be a regular call to a function
    1805        11359 :   translated
    1806        11359 :     = Backend::call_expression (fn_address, args, nullptr, expr.get_locus ());
    1807        11359 : }
    1808              : 
    1809              : void
    1810         2665 : CompileExpr::visit (HIR::MethodCallExpr &expr)
    1811              : {
    1812              :   // method receiver
    1813         2665 :   tree self = CompileExpr::Compile (expr.get_receiver (), ctx);
    1814              : 
    1815              :   // lookup the expected function type
    1816         2665 :   TyTy::BaseType *lookup_fntype = nullptr;
    1817         2665 :   bool ok = ctx->get_tyctx ()->lookup_type (
    1818         2665 :     expr.get_method_name ().get_mappings ().get_hirid (), &lookup_fntype);
    1819         2665 :   rust_assert (ok);
    1820         2665 :   rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF);
    1821         2665 :   TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
    1822              : 
    1823         2665 :   TyTy::BaseType *receiver = nullptr;
    1824         2665 :   ok = ctx->get_tyctx ()->lookup_type (
    1825         2665 :     expr.get_receiver ().get_mappings ().get_hirid (), &receiver);
    1826         2665 :   rust_assert (ok);
    1827              : 
    1828              :   // lookup the autoderef mappings
    1829         2665 :   HirId autoderef_mappings_id
    1830         2665 :     = expr.get_receiver ().get_mappings ().get_hirid ();
    1831         2665 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    1832         2665 :   ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
    1833              :                                                      &adjustments);
    1834         2665 :   rust_assert (ok);
    1835              : 
    1836              :   // apply adjustments for the fn call
    1837         2665 :   self = resolve_adjustments (*adjustments, self,
    1838         2665 :                               expr.get_receiver ().get_locus ());
    1839              : 
    1840         2665 :   if (adjustments != nullptr && !adjustments->empty ())
    1841          620 :     receiver = adjustments->back ().get_expected ();
    1842              : 
    1843         2665 :   enum
    1844              :   {
    1845              :     DYN,
    1846              :     DYN_BOX,
    1847              :     NOT_DYN,
    1848         2665 :   } is_dyn_dispatch
    1849              :     = NOT_DYN;
    1850         2665 :   const TyTy::DynamicObjectType *dyn = nullptr;
    1851         2665 :   if (receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
    1852              :     {
    1853          209 :       is_dyn_dispatch = DYN;
    1854          209 :       dyn
    1855          209 :         = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
    1856              :     }
    1857         2456 :   else if (auto inner = TyTy::try_get_box_inner_type (receiver->get_root ()))
    1858              :     {
    1859            1 :       if ((*inner)->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
    1860              :         {
    1861            1 :           is_dyn_dispatch = DYN_BOX;
    1862            1 :           dyn = static_cast<const TyTy::DynamicObjectType *> (
    1863            1 :             (*inner)->get_root ());
    1864              :         }
    1865              :     }
    1866              : 
    1867         2665 :   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
    1868         2665 :   if (is_generic_receiver)
    1869              :     {
    1870           77 :       TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
    1871           77 :       receiver = p->resolve ();
    1872              :     }
    1873              : 
    1874         2665 :   tree fn_expr = error_mark_node;
    1875         2665 :   if (is_dyn_dispatch == NOT_DYN)
    1876              :     // lookup compiled functions since it may have already been compiled
    1877         2455 :     fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
    1878              :   else
    1879              :     {
    1880          210 :       tree target_self
    1881              :         = is_dyn_dispatch == DYN
    1882          210 :             ? self
    1883            1 :             : build_box_inner_ptr (self, expr.get_receiver ().get_locus ());
    1884              : 
    1885          210 :       fn_expr = get_fn_addr_from_dyn (dyn, receiver, fntype, target_self,
    1886              :                                       expr.get_locus ());
    1887              : 
    1888          210 :       self = get_receiver_from_dyn (dyn, receiver, fntype, target_self,
    1889              :                                     expr.get_locus ());
    1890              :     }
    1891              : 
    1892         2665 :   std::vector<tree> args;
    1893         2665 :   args.push_back (self); // adjusted self
    1894              : 
    1895              :   // normal args
    1896         7091 :   for (size_t i = 0; i < expr.get_arguments ().size (); i++)
    1897              :     {
    1898         1761 :       auto &argument = expr.get_arguments ().at (i);
    1899         1761 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    1900              : 
    1901              :       // assignments are coercion sites so lets convert the rvalue if
    1902              :       // necessary, offset from the already adjusted implicit self
    1903         1761 :       bool ok;
    1904         1761 :       TyTy::BaseType *expected = fntype->param_at (i + 1).get_type ();
    1905              : 
    1906         1761 :       TyTy::BaseType *actual = nullptr;
    1907         1761 :       ok = ctx->get_tyctx ()->lookup_type (
    1908         1761 :         argument->get_mappings ().get_hirid (), &actual);
    1909         1761 :       rust_assert (ok);
    1910              : 
    1911              :       // coerce it if required
    1912         1761 :       location_t lvalue_locus
    1913         1761 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1914         1761 :       location_t rvalue_locus = argument->get_locus ();
    1915         1761 :       rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1916              :                               actual, expected, lvalue_locus, rvalue_locus);
    1917              : 
    1918              :       // add it to the list
    1919         1761 :       args.push_back (rvalue);
    1920              :     }
    1921              : 
    1922         2665 :   translated
    1923         2665 :     = Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ());
    1924         2665 : }
    1925              : 
    1926              : tree
    1927          210 : CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn,
    1928              :                                    TyTy::BaseType *receiver,
    1929              :                                    TyTy::FnType *fntype, tree receiver_ref,
    1930              :                                    location_t expr_locus)
    1931              : {
    1932          210 :   size_t offs = 0;
    1933          210 :   const Resolver::TraitItemReference *ref = nullptr;
    1934          268 :   for (auto &bound : dyn->get_object_items ())
    1935              :     {
    1936          268 :       const Resolver::TraitItemReference *item = bound.first;
    1937          268 :       auto t = item->get_tyty ();
    1938          268 :       rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF);
    1939          268 :       auto ft = static_cast<TyTy::FnType *> (t);
    1940              : 
    1941          478 :       if (ft->get_id () == fntype->get_id ())
    1942              :         {
    1943              :           ref = item;
    1944              :           break;
    1945              :         }
    1946           58 :       offs++;
    1947          210 :     }
    1948              : 
    1949          210 :   if (ref == nullptr)
    1950            0 :     return error_mark_node;
    1951              : 
    1952              :   // cast it to the correct fntype
    1953          210 :   tree expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true);
    1954          210 :   tree idx = build_int_cst (size_type_node, offs);
    1955              : 
    1956          210 :   tree vtable_ptr
    1957          210 :     = Backend::struct_field_expression (receiver_ref, 1, expr_locus);
    1958          210 :   tree vtable_struct_type = TREE_TYPE (TREE_TYPE (vtable_ptr));
    1959          210 :   rust_assert (TREE_CODE (vtable_struct_type) == RECORD_TYPE);
    1960          210 :   tree vtable_field = TYPE_FIELDS (vtable_struct_type);
    1961          898 :   for (size_t i = 0; i < offs + 3; i++) // drop, size, align, [methods]
    1962          688 :     vtable_field = DECL_CHAIN (vtable_field);
    1963          210 :   rust_assert (vtable_field != NULL_TREE);
    1964          210 :   tree vtable = build_fold_indirect_ref_loc (expr_locus, vtable_ptr);
    1965          210 :   tree vtable_field_access
    1966          210 :     = build3_loc (expr_locus, COMPONENT_REF, TREE_TYPE (vtable_field), vtable,
    1967              :                   vtable_field, NULL_TREE);
    1968              : 
    1969          210 :   tree vcall = build3_loc (expr_locus, OBJ_TYPE_REF, expected_fntype,
    1970              :                            vtable_field_access, receiver_ref, idx);
    1971              : 
    1972          210 :   return vcall;
    1973              : }
    1974              : 
    1975              : tree
    1976          210 : CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
    1977              :                                     TyTy::BaseType *receiver,
    1978              :                                     TyTy::FnType *fntype, tree receiver_ref,
    1979              :                                     location_t expr_locus)
    1980              : {
    1981              :   // access the offs + 1 for the fnptr and offs=0 for the reciever obj
    1982          210 :   return Backend::struct_field_expression (receiver_ref, 0, expr_locus);
    1983              : }
    1984              : 
    1985              : tree
    1986         1219 : CompileExpr::resolve_operator_overload (
    1987              :   LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, tree rhs,
    1988              :   HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr,
    1989              :   HIR::PathIdentSegment specified_segment)
    1990              : {
    1991         1219 :   TyTy::FnType *fntype;
    1992         1219 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    1993         1219 :     expr.get_mappings ().get_hirid (), &fntype);
    1994         1219 :   rust_assert (is_op_overload);
    1995              : 
    1996         1219 :   TyTy::BaseType *receiver = nullptr;
    1997         1219 :   bool ok
    1998         1219 :     = ctx->get_tyctx ()->lookup_type (lhs_expr.get_mappings ().get_hirid (),
    1999              :                                       &receiver);
    2000         1219 :   rust_assert (ok);
    2001              : 
    2002         1219 :   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
    2003         1219 :   if (is_generic_receiver)
    2004              :     {
    2005           14 :       TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
    2006           14 :       receiver = p->resolve ();
    2007              :     }
    2008              : 
    2009              :   // lookup compiled functions since it may have already been compiled
    2010         1219 :   HIR::PathIdentSegment segment_name
    2011         1219 :     = specified_segment.is_error ()
    2012         1563 :         ? HIR::PathIdentSegment (LangItem::ToString (lang_item_type))
    2013         1219 :         : specified_segment;
    2014         1219 :   tree fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
    2015              : 
    2016              :   // lookup the autoderef mappings
    2017         1219 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    2018         1219 :   ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
    2019         1219 :     expr.get_lvalue_mappings ().get_hirid (), &adjustments);
    2020         1219 :   rust_assert (ok);
    2021              : 
    2022              :   // apply adjustments for the fn call
    2023         1219 :   tree self = resolve_adjustments (*adjustments, lhs, lhs_expr.get_locus ());
    2024              : 
    2025         1219 :   std::vector<tree> args;
    2026         1219 :   args.push_back (self); // adjusted self
    2027         1219 :   if (rhs != nullptr)    // can be null for negation_expr (unary ones)
    2028         1156 :     args.push_back (rhs);
    2029              : 
    2030         1219 :   return Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ());
    2031         1219 : }
    2032              : 
    2033              : tree
    2034          928 : CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr,
    2035              :                                    const TyTy::BaseType *tyty)
    2036              : {
    2037          928 :   rust_assert (expr.get_lit_type () == HIR::Literal::BOOL);
    2038              : 
    2039          928 :   const auto literal_value = expr.get_literal ();
    2040         1856 :   bool bval = literal_value.as_string ().compare ("true") == 0;
    2041          928 :   return Backend::boolean_constant_expression (bval);
    2042          928 : }
    2043              : 
    2044              : tree
    2045        19981 : CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
    2046              :                                       const TyTy::BaseType *tyty)
    2047              : {
    2048        19981 :   rust_assert (expr.get_lit_type () == HIR::Literal::INT);
    2049        19981 :   const auto &literal_value = expr.get_literal ();
    2050        19981 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    2051              : 
    2052        19981 :   std::string s = literal_value.as_string ();
    2053        19981 :   s.erase (std::remove (s.begin (), s.end (), '_'), s.end ());
    2054              : 
    2055        19981 :   int base = 0;
    2056        19981 :   mpz_t ival;
    2057        19981 :   if (mpz_init_set_str (ival, s.c_str (), base) != 0)
    2058              :     {
    2059            0 :       rust_error_at (expr.get_locus (), "failed to load number literal");
    2060            0 :       return error_mark_node;
    2061              :     }
    2062        19981 :   if (expr.is_negative ())
    2063          660 :     mpz_neg (ival, ival);
    2064              : 
    2065        19981 :   mpz_t type_min, type_max;
    2066        19981 :   mpz_init (type_min);
    2067        19981 :   mpz_init (type_max);
    2068        19981 :   get_type_static_bounds (type, type_min, type_max);
    2069              : 
    2070        19981 :   if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
    2071              :     {
    2072            2 :       rust_error_at (expr.get_locus (),
    2073              :                      "integer overflows the respective type %qs",
    2074            2 :                      tyty->get_name ().c_str ());
    2075            2 :       mpz_clear (type_min);
    2076            2 :       mpz_clear (type_max);
    2077            2 :       mpz_clear (ival);
    2078            2 :       return error_mark_node;
    2079              :     }
    2080              : 
    2081        19979 :   tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
    2082        19979 :   mpz_clear (type_min);
    2083        19979 :   mpz_clear (type_max);
    2084        19979 :   mpz_clear (ival);
    2085              : 
    2086        19979 :   return result;
    2087        19981 : }
    2088              : 
    2089              : tree
    2090          999 : CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
    2091              :                                     const TyTy::BaseType *tyty)
    2092              : {
    2093          999 :   rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
    2094          999 :   const auto literal_value = expr.get_literal ();
    2095              : 
    2096          999 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    2097              : 
    2098          999 :   mpfr_t fval;
    2099         2997 :   if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
    2100              :                          MPFR_RNDN)
    2101          999 :       != 0)
    2102              :     {
    2103            0 :       rust_error_at (expr.get_locus (), "bad number in literal");
    2104            0 :       return error_mark_node;
    2105              :     }
    2106          999 :   if (expr.is_negative ())
    2107            6 :     mpfr_neg (fval, fval, MPFR_RNDN);
    2108              : 
    2109              :   // taken from:
    2110              :   // see go/gofrontend/expressions.cc:check_float_type
    2111          999 :   bool real_value_overflow;
    2112              : 
    2113          999 :   if (mpfr_regular_p (fval) != 0)
    2114              :     {
    2115          893 :       mpfr_exp_t exp = mpfr_get_exp (fval);
    2116          893 :       mpfr_exp_t min_exp;
    2117          893 :       mpfr_exp_t max_exp;
    2118              : 
    2119              :       /*
    2120              :        * By convention, the radix point of the significand is just before the
    2121              :        * first digit (which is always 1 due to normalization), like in the C
    2122              :        * language, but unlike in IEEE 754 (thus, for a given number, the
    2123              :        * exponent values in MPFR and in IEEE 754 differ by 1).
    2124              :        */
    2125          893 :       switch (TYPE_PRECISION (type))
    2126              :         {
    2127              :         case 32:
    2128              :           min_exp = -128 + 1;
    2129              :           max_exp = 127 + 1;
    2130              :           break;
    2131          321 :         case 64:
    2132          321 :           min_exp = -1024 + 1;
    2133          321 :           max_exp = 1023 + 1;
    2134          321 :           break;
    2135            0 :         default:
    2136            0 :           rust_error_at (expr.get_locus (),
    2137              :                          "precision of type %<%s%> not supported",
    2138            0 :                          tyty->get_name ().c_str ());
    2139            0 :           return error_mark_node;
    2140              :         }
    2141          893 :       real_value_overflow = exp < min_exp || exp > max_exp;
    2142              :     }
    2143              :   else
    2144              :     {
    2145              :       real_value_overflow = false;
    2146              :     }
    2147              : 
    2148          999 :   REAL_VALUE_TYPE r1;
    2149          999 :   real_from_mpfr (&r1, fval, type, GMP_RNDN);
    2150          999 :   REAL_VALUE_TYPE r2;
    2151          999 :   real_convert (&r2, TYPE_MODE (type), &r1);
    2152              : 
    2153          999 :   tree real_value = build_real (type, r2);
    2154          999 :   if (TREE_OVERFLOW (real_value) || real_value_overflow)
    2155              :     {
    2156            1 :       rust_error_at (expr.get_locus (),
    2157              :                      "decimal overflows the respective type %qs",
    2158            1 :                      tyty->get_name ().c_str ());
    2159            1 :       return error_mark_node;
    2160              :     }
    2161              : 
    2162              :   return real_value;
    2163          999 : }
    2164              : 
    2165              : tree
    2166          183 : CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr,
    2167              :                                    const TyTy::BaseType *tyty)
    2168              : {
    2169          183 :   rust_assert (expr.get_lit_type () == HIR::Literal::CHAR);
    2170          183 :   const auto literal_value = expr.get_literal ();
    2171              : 
    2172              :   // FIXME needs wchar_t
    2173          366 :   char c = literal_value.as_string ().c_str ()[0];
    2174          183 :   return Backend::wchar_constant_expression (c);
    2175          183 : }
    2176              : 
    2177              : tree
    2178          408 : CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr,
    2179              :                                    const TyTy::BaseType *tyty)
    2180              : {
    2181          408 :   rust_assert (expr.get_lit_type () == HIR::Literal::BYTE);
    2182          408 :   const auto literal_value = expr.get_literal ();
    2183              : 
    2184          408 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    2185          816 :   char c = literal_value.as_string ().c_str ()[0];
    2186          408 :   return build_int_cst (type, c);
    2187          408 : }
    2188              : 
    2189              : tree
    2190         2379 : CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr,
    2191              :                                      const TyTy::BaseType *tyty)
    2192              : {
    2193         2379 :   tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty);
    2194              : 
    2195         2379 :   rust_assert (expr.get_lit_type () == HIR::Literal::STRING);
    2196         2379 :   const auto literal_value = expr.get_literal ();
    2197              : 
    2198         4758 :   auto base = Backend::string_constant_expression (literal_value.as_string ());
    2199         2379 :   tree data = address_expression (base, expr.get_locus ());
    2200              : 
    2201         2379 :   TyTy::BaseType *usize = nullptr;
    2202         2379 :   bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
    2203         2379 :   rust_assert (ok);
    2204         2379 :   tree type = TyTyResolveCompile::compile (ctx, usize);
    2205              : 
    2206         4758 :   tree size = build_int_cstu (type, literal_value.as_string ().size ());
    2207              : 
    2208         2379 :   return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
    2209         2379 :                                           expr.get_locus ());
    2210         2379 : }
    2211              : 
    2212              : tree
    2213           35 : CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
    2214              :                                           const TyTy::BaseType *tyty)
    2215              : {
    2216           35 :   rust_assert (expr.get_lit_type () == HIR::Literal::BYTE_STRING);
    2217              : 
    2218              :   // the type here is &[ty; capacity]
    2219           35 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::REF);
    2220           35 :   const auto ref_tyty = static_cast<const TyTy::ReferenceType *> (tyty);
    2221           35 :   auto base_tyty = ref_tyty->get_base ();
    2222           35 :   rust_assert (base_tyty->get_kind () == TyTy::TypeKind::ARRAY);
    2223           35 :   auto array_tyty = static_cast<TyTy::ArrayType *> (base_tyty);
    2224              : 
    2225           35 :   std::string value_str = expr.get_literal ().as_string ();
    2226           35 :   std::vector<tree> vals;
    2227           35 :   std::vector<unsigned long> indexes;
    2228          273 :   for (size_t i = 0; i < value_str.size (); i++)
    2229              :     {
    2230          238 :       char b = value_str.at (i);
    2231          238 :       tree bb = Backend::char_constant_expression (b);
    2232          238 :       vals.push_back (bb);
    2233          238 :       indexes.push_back (i);
    2234              :     }
    2235              : 
    2236           35 :   tree array_type = TyTyResolveCompile::compile (ctx, array_tyty);
    2237           35 :   tree constructed
    2238           35 :     = Backend::array_constructor_expression (array_type, indexes, vals,
    2239              :                                              expr.get_locus ());
    2240              : 
    2241           35 :   return address_expression (constructed, expr.get_locus ());
    2242           35 : }
    2243              : 
    2244              : tree
    2245           14 : CompileExpr::compile_c_string_literal (const HIR::LiteralExpr &expr,
    2246              :                                        const TyTy::BaseType *tyty)
    2247              : {
    2248              :   // Copied from compile_string_literal
    2249           14 :   tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty);
    2250              : 
    2251           14 :   rust_assert (expr.get_lit_type () == HIR::Literal::C_STRING);
    2252           14 :   const auto literal_value = expr.get_literal ();
    2253              : 
    2254           28 :   auto base = Backend::string_constant_expression (literal_value.as_string ());
    2255           14 :   tree data = address_expression (base, expr.get_locus ());
    2256              : 
    2257           14 :   TyTy::BaseType *usize = nullptr;
    2258           14 :   bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
    2259           14 :   rust_assert (ok);
    2260           14 :   tree type = TyTyResolveCompile::compile (ctx, usize);
    2261              : 
    2262              :   // +1 for null terminator, unlike Rust string literals.
    2263           28 :   tree size = build_int_cstu (type, literal_value.as_string ().size () + 1);
    2264              : 
    2265           14 :   return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
    2266           14 :                                           expr.get_locus ());
    2267           14 : }
    2268              : 
    2269              : tree
    2270           18 : CompileExpr::compile_transparent_field_access (TyTy::VariantDef *variant,
    2271              :                                                location_t locus,
    2272              :                                                tree source_expr)
    2273              : {
    2274           18 :   const TyTy::StructFieldType *field = variant->get_field_at_index (0);
    2275           18 :   tree field_type = TyTyResolveCompile::compile (ctx, field->get_field_type ());
    2276           18 :   return fold_build1_loc (locus, VIEW_CONVERT_EXPR, field_type, source_expr);
    2277              : }
    2278              : 
    2279              : tree
    2280         5380 : CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
    2281              :                                    location_t location)
    2282              : {
    2283         5380 :   if (type_to_cast_to == error_mark_node || expr_tree == error_mark_node
    2284        10760 :       || TREE_TYPE (expr_tree) == error_mark_node)
    2285              :     return error_mark_node;
    2286              : 
    2287         5380 :   if (Backend::type_size (type_to_cast_to) == 0
    2288         5380 :       || TREE_TYPE (expr_tree) == void_type_node)
    2289              :     {
    2290              :       // Do not convert zero-sized types.
    2291              :       return expr_tree;
    2292              :     }
    2293         5380 :   else if (TREE_CODE (type_to_cast_to) == INTEGER_TYPE)
    2294              :     {
    2295         1530 :       tree cast = convert_to_integer (type_to_cast_to, expr_tree);
    2296              :       // FIXME check for TREE_OVERFLOW?
    2297         1530 :       return cast;
    2298              :     }
    2299         3850 :   else if (TREE_CODE (type_to_cast_to) == REAL_TYPE)
    2300              :     {
    2301            9 :       tree cast = convert_to_real (type_to_cast_to, expr_tree);
    2302              :       // FIXME
    2303              :       // We might need to check that the tree is MAX val and thusly saturate it
    2304              :       // to inf. we can get the bounds and check the value if its >= or <= to
    2305              :       // the min and max bounds
    2306              :       //
    2307              :       // https://github.com/Rust-GCC/gccrs/issues/635
    2308            9 :       return cast;
    2309              :     }
    2310         3841 :   else if (TREE_CODE (type_to_cast_to) == COMPLEX_TYPE)
    2311              :     {
    2312            0 :       return convert_to_complex (type_to_cast_to, expr_tree);
    2313              :     }
    2314         3841 :   else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
    2315         3841 :            && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
    2316              :     {
    2317           12 :       return convert_to_pointer (type_to_cast_to, expr_tree);
    2318              :     }
    2319         3829 :   else if (TREE_CODE (type_to_cast_to) == RECORD_TYPE
    2320         3829 :            || TREE_CODE (type_to_cast_to) == ARRAY_TYPE)
    2321              :     {
    2322         1750 :       return fold_build1_loc (location, VIEW_CONVERT_EXPR, type_to_cast_to,
    2323         1750 :                               expr_tree);
    2324              :     }
    2325         2079 :   else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
    2326         2079 :            && RS_DST_FLAG (TREE_TYPE (expr_tree)))
    2327              :     {
    2328              :       // returning a raw cast using NOP_EXPR seems to resut in an ICE:
    2329              :       //
    2330              :       // Analyzing compilation unit
    2331              :       // Performing interprocedural optimizations
    2332              :       //  <*free_lang_data> {heap 2644k} <visibility> {heap 2644k}
    2333              :       //  <build_ssa_passes> {heap 2644k} <opt_local_passes> {heap 2644k}during
    2334              :       //  GIMPLE pass: cddce
    2335              :       // In function ‘*T::as_ptr<i32>’:
    2336              :       // rust1: internal compiler error: in propagate_necessity, at
    2337              :       // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity
    2338              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:984
    2339              :       // 0x1d5e180 perform_tree_ssa_dce
    2340              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1876
    2341              :       // 0x1d5e2c8 tree_ssa_cd_dce
    2342              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1920
    2343              :       // 0x1d5e49a execute
    2344              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1992
    2345              : 
    2346              :       // this is returning the direct raw pointer of the slice an assumes a very
    2347              :       // specific layout
    2348         1746 :       return Backend::struct_field_expression (expr_tree, 0, location);
    2349              :     }
    2350              : 
    2351          333 :   return fold_convert_loc (location, type_to_cast_to, expr_tree);
    2352              : }
    2353              : 
    2354              : void
    2355          407 : CompileExpr::visit (HIR::ArrayExpr &expr)
    2356              : {
    2357          407 :   TyTy::BaseType *tyty = nullptr;
    2358          407 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    2359              :                                        &tyty))
    2360              :     {
    2361            0 :       rust_fatal_error (expr.get_locus (),
    2362              :                         "did not resolve type for this array expr");
    2363          293 :       return;
    2364              :     }
    2365              : 
    2366          407 :   tree array_type = TyTyResolveCompile::compile (ctx, tyty);
    2367          407 :   if (TREE_CODE (array_type) != ARRAY_TYPE)
    2368              :     {
    2369            0 :       translated = error_mark_node;
    2370            0 :       return;
    2371              :     }
    2372              : 
    2373          407 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY);
    2374          407 :   const TyTy::ArrayType &array_tyty
    2375              :     = static_cast<const TyTy::ArrayType &> (*tyty);
    2376              : 
    2377          407 :   HIR::ArrayElems &elements = expr.get_internal_elements ();
    2378          407 :   switch (elements.get_array_expr_type ())
    2379              :     {
    2380          293 :     case HIR::ArrayElems::ArrayExprType::VALUES:
    2381          293 :       {
    2382          293 :         HIR::ArrayElemsValues &elems
    2383              :           = static_cast<HIR::ArrayElemsValues &> (elements);
    2384          293 :         translated
    2385          293 :           = array_value_expr (expr.get_locus (), array_tyty, array_type, elems);
    2386              :       }
    2387          293 :       return;
    2388              : 
    2389          114 :     case HIR::ArrayElems::ArrayExprType::COPIED:
    2390          114 :       HIR::ArrayElemsCopied &elems
    2391              :         = static_cast<HIR::ArrayElemsCopied &> (elements);
    2392          114 :       translated
    2393          114 :         = array_copied_expr (expr.get_locus (), array_tyty, array_type, elems);
    2394              :     }
    2395              : }
    2396              : 
    2397              : tree
    2398          293 : CompileExpr::array_value_expr (location_t expr_locus,
    2399              :                                const TyTy::ArrayType &array_tyty,
    2400              :                                tree array_type, HIR::ArrayElemsValues &elems)
    2401              : {
    2402          293 :   std::vector<unsigned long> indexes;
    2403          293 :   std::vector<tree> constructor;
    2404          293 :   size_t i = 0;
    2405         1782 :   for (auto &elem : elems.get_values ())
    2406              :     {
    2407         1490 :       tree translated_expr = CompileExpr::Compile (*elem, ctx);
    2408         1490 :       if (translated_expr == error_mark_node)
    2409              :         {
    2410            1 :           rich_location r (line_table, expr_locus);
    2411            1 :           r.add_fixit_replace (elem->get_locus (), "not a value");
    2412            1 :           rust_error_at (r, ErrorCode::E0423, "expected value");
    2413            1 :           return error_mark_node;
    2414            1 :         }
    2415              : 
    2416         1489 :       constructor.push_back (translated_expr);
    2417         1489 :       indexes.push_back (i++);
    2418              :     }
    2419              : 
    2420          292 :   return Backend::array_constructor_expression (array_type, indexes,
    2421          292 :                                                 constructor, expr_locus);
    2422          293 : }
    2423              : 
    2424              : tree
    2425          114 : CompileExpr::array_copied_expr (location_t expr_locus,
    2426              :                                 const TyTy::ArrayType &array_tyty,
    2427              :                                 tree array_type, HIR::ArrayElemsCopied &elems)
    2428              : {
    2429              :   //  see gcc/cp/typeck2.cc:1369-1401
    2430          114 :   gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
    2431          114 :   tree domain = TYPE_DOMAIN (array_type);
    2432          114 :   if (!domain)
    2433            0 :     return error_mark_node;
    2434              : 
    2435          114 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
    2436              :     {
    2437            0 :       rust_error_at (expr_locus, "non const capacity domain %qT", array_type);
    2438            0 :       return error_mark_node;
    2439              :     }
    2440              : 
    2441          114 :   auto capacity_ty = array_tyty.get_capacity ();
    2442              : 
    2443              :   // Check if capacity is a const type
    2444          114 :   if (capacity_ty->get_kind () != TyTy::TypeKind::CONST)
    2445              :     {
    2446            0 :       rust_error_at (array_tyty.get_locus (),
    2447              :                      "array capacity is not a const type");
    2448            0 :       return error_mark_node;
    2449              :     }
    2450              : 
    2451          114 :   auto *capacity_const = capacity_ty->as_const_type ();
    2452              : 
    2453          114 :   rust_assert (capacity_const->const_kind ()
    2454              :                == TyTy::BaseConstType::ConstKind::Value);
    2455          114 :   auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
    2456          114 :   auto cap_tree = capacity_value.get_value ();
    2457          114 :   if (error_operand_p (cap_tree) || !TREE_CONSTANT (cap_tree))
    2458              :     {
    2459            0 :       rust_error_at (expr_locus, "non const num copies %qT", cap_tree);
    2460            0 :       return error_mark_node;
    2461              :     }
    2462              : 
    2463              :   // get the compiled value
    2464          114 :   tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
    2465              : 
    2466          114 :   tree max_domain = TYPE_MAX_VALUE (domain);
    2467          114 :   tree min_domain = TYPE_MIN_VALUE (domain);
    2468              : 
    2469          114 :   auto max = wi::to_offset (max_domain);
    2470          114 :   auto min = wi::to_offset (min_domain);
    2471          114 :   auto precision = TYPE_PRECISION (TREE_TYPE (domain));
    2472          114 :   auto sign = TYPE_SIGN (TREE_TYPE (domain));
    2473          114 :   unsigned HOST_WIDE_INT len
    2474          114 :     = wi::ext (max - min + 1, precision, sign).to_uhwi ();
    2475              : 
    2476              :   // In a const context we must initialize the entire array, which entails
    2477              :   // allocating for each element. If the user wants a huge array, we will OOM
    2478              :   // and die horribly.
    2479          114 :   if (ctx->const_context_p ())
    2480              :     {
    2481            9 :       size_t idx = 0;
    2482              : 
    2483            9 :       std::vector<unsigned long> indexes;
    2484            9 :       std::vector<tree> constructor;
    2485              : 
    2486            9 :       indexes.reserve (len);
    2487            9 :       constructor.reserve (len);
    2488          144 :       for (unsigned HOST_WIDE_INT i = 0; i < len; i++)
    2489              :         {
    2490          126 :           constructor.push_back (translated_expr);
    2491          126 :           indexes.push_back (idx++);
    2492              :         }
    2493              : 
    2494            9 :       return Backend::array_constructor_expression (array_type, indexes,
    2495              :                                                     constructor, expr_locus);
    2496            9 :     }
    2497              : 
    2498              :   else
    2499              :     {
    2500              :       // Create a new block scope in which to initialize the array
    2501          105 :       tree fndecl = NULL_TREE;
    2502          105 :       if (ctx->in_fn ())
    2503          105 :         fndecl = ctx->peek_fn ().fndecl;
    2504              : 
    2505          105 :       std::vector<Bvariable *> locals;
    2506          105 :       tree enclosing_scope = ctx->peek_enclosing_scope ();
    2507          105 :       tree init_block = Backend::block (fndecl, enclosing_scope, locals,
    2508              :                                         expr_locus, expr_locus);
    2509          105 :       ctx->push_block (init_block);
    2510              : 
    2511          105 :       tree tmp;
    2512          105 :       tree stmts
    2513          105 :         = Backend::array_initializer (fndecl, init_block, array_type, cap_tree,
    2514              :                                       translated_expr, &tmp, expr_locus);
    2515          105 :       ctx->add_statement (stmts);
    2516              : 
    2517          105 :       tree block = ctx->pop_block ();
    2518              : 
    2519              :       // The result is a compound expression which creates a temporary array,
    2520              :       // initializes all the elements in a loop, and then yeilds the array.
    2521          105 :       return Backend::compound_expression (block, tmp, expr_locus);
    2522          105 :     }
    2523              : }
    2524              : 
    2525              : tree
    2526        42743 : HIRCompileBase::resolve_adjustments (
    2527              :   std::vector<Resolver::Adjustment> &adjustments, tree expression,
    2528              :   location_t locus)
    2529              : {
    2530        42743 :   tree e = expression;
    2531        45167 :   for (auto &adjustment : adjustments)
    2532              :     {
    2533         2425 :       if (e == error_mark_node)
    2534              :         return error_mark_node;
    2535              : 
    2536         2424 :       switch (adjustment.get_type ())
    2537              :         {
    2538              :         case Resolver::Adjustment::AdjustmentType::ERROR:
    2539              :           return error_mark_node;
    2540              : 
    2541         1769 :         case Resolver::Adjustment::AdjustmentType::IMM_REF:
    2542         1769 :         case Resolver::Adjustment::AdjustmentType::MUT_REF:
    2543         1769 :           {
    2544         1769 :             if (!RS_DST_FLAG (TREE_TYPE (e)))
    2545              :               {
    2546         1504 :                 e = address_expression (e, locus);
    2547              :               }
    2548              :           }
    2549              :           break;
    2550              : 
    2551           62 :         case Resolver::Adjustment::AdjustmentType::DEREF:
    2552           62 :         case Resolver::Adjustment::AdjustmentType::DEREF_MUT:
    2553           62 :           e = resolve_deref_adjustment (adjustment, e, locus);
    2554           62 :           break;
    2555              : 
    2556          327 :         case Resolver::Adjustment::AdjustmentType::INDIRECTION:
    2557          327 :           e = resolve_indirection_adjustment (adjustment, e, locus);
    2558          327 :           break;
    2559              : 
    2560          266 :         case Resolver::Adjustment::AdjustmentType::UNSIZE:
    2561          266 :           e = resolve_unsized_adjustment (adjustment, e, locus);
    2562          266 :           break;
    2563              :         }
    2564              :     }
    2565              : 
    2566              :   return e;
    2567              : }
    2568              : 
    2569              : tree
    2570           62 : HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
    2571              :                                           tree expression, location_t locus)
    2572              : {
    2573           62 :   rust_assert (adjustment.is_deref_adjustment ()
    2574              :                || adjustment.is_deref_mut_adjustment ());
    2575           62 :   if (!adjustment.has_operator_overload ())
    2576              :     {
    2577            6 :       if (TyTy::try_get_box_inner_type (adjustment.get_actual ()))
    2578              :         {
    2579            6 :           expression = build_box_inner_ptr (expression, locus);
    2580            6 :           if (TREE_CODE (TREE_TYPE (expression)) == POINTER_TYPE
    2581            6 :               || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE)
    2582            2 :             expression = indirect_expression (expression, locus);
    2583              :           return expression;
    2584            0 :           ;
    2585              :         }
    2586            0 :       rust_assert (false);
    2587              :     }
    2588              : 
    2589           56 :   TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
    2590           56 :   TyTy::BaseType *receiver = adjustment.get_actual ();
    2591           56 :   tree fn_address = resolve_method_address (lookup, receiver, locus);
    2592              : 
    2593              :   // does it need a reference to call
    2594           56 :   tree adjusted_argument = expression;
    2595           56 :   bool needs_borrow = adjustment.get_deref_adjustment_type ()
    2596           56 :                       != Resolver::Adjustment::AdjustmentType::ERROR;
    2597           56 :   if (needs_borrow)
    2598              :     {
    2599           56 :       adjusted_argument = address_expression (expression, locus);
    2600              :     }
    2601              : 
    2602              :   // make the call
    2603           56 :   return Backend::call_expression (fn_address, {adjusted_argument}, nullptr,
    2604              :                                    locus);
    2605              : }
    2606              : 
    2607              : tree
    2608          327 : HIRCompileBase::resolve_indirection_adjustment (
    2609              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2610              : {
    2611          327 :   return indirect_expression (expression, locus);
    2612              : }
    2613              : 
    2614              : tree
    2615          275 : HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment,
    2616              :                                             tree expression, location_t locus)
    2617              : {
    2618          275 :   bool expect_slice
    2619          275 :     = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE;
    2620          275 :   bool expect_dyn
    2621          275 :     = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC;
    2622          275 :   bool expect_adt
    2623          275 :     = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::ADT;
    2624              : 
    2625              :   // assumes this is an array
    2626          275 :   tree expr_type = TREE_TYPE (expression);
    2627          275 :   if (expect_slice)
    2628              :     {
    2629           87 :       rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
    2630           87 :       return resolve_unsized_slice_adjustment (adjustment, expression, locus);
    2631              :     }
    2632              : 
    2633          188 :   if (expect_adt)
    2634           14 :     return resolve_unsized_adt_adjustment (adjustment, expression, locus);
    2635              : 
    2636          174 :   rust_assert (expect_dyn);
    2637          174 :   return resolve_unsized_dyn_adjustment (adjustment, expression, locus);
    2638              : }
    2639              : 
    2640              : tree
    2641           87 : HIRCompileBase::resolve_unsized_slice_adjustment (
    2642              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2643              : {
    2644              :   // assumes this is an array
    2645           87 :   tree expr_type = TREE_TYPE (expression);
    2646           87 :   rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
    2647              : 
    2648              :   // takes an array and returns a fat-pointer so this becomes a constructor
    2649              :   // expression
    2650           87 :   rust_assert (adjustment.get_expected ()->get_kind ()
    2651              :                == TyTy::TypeKind::SLICE);
    2652           87 :   tree fat_pointer
    2653           87 :     = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
    2654              : 
    2655              :   // make a constructor for this
    2656           87 :   tree data = address_expression (expression, locus);
    2657              : 
    2658              :   // fetch the size from the domain
    2659           87 :   tree domain = TYPE_DOMAIN (expr_type);
    2660           87 :   unsigned HOST_WIDE_INT array_size
    2661          174 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
    2662          174 :                  - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
    2663           87 :                TYPE_PRECISION (TREE_TYPE (domain)),
    2664           87 :                TYPE_SIGN (TREE_TYPE (domain)))
    2665           87 :         .to_uhwi ();
    2666           87 :   tree size = build_int_cstu (size_type_node, array_size);
    2667              : 
    2668           87 :   return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
    2669           87 :                                           locus);
    2670              : }
    2671              : 
    2672              : tree
    2673           20 : HIRCompileBase::resolve_unsized_adt_adjustment (
    2674              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2675              : {
    2676              :   /*
    2677              :    * FIXME: This method is implemented as a temporary workaround to enable the
    2678              :    * compilation of intra-ADT conversions for the `coerce_unsized` lang item.
    2679              :    */
    2680              : 
    2681           20 :   auto source_adt
    2682           20 :     = static_cast<const TyTy::ADTType *> (adjustment.get_actual ());
    2683           20 :   auto target_adt
    2684           20 :     = static_cast<const TyTy::ADTType *> (adjustment.get_expected ());
    2685              : 
    2686           20 :   if (target_adt->is_unsized ())
    2687              :     {
    2688            9 :       TyTy::TyVar t_tyvar = TyTy::TyVar::get_implicit_infer_var (locus);
    2689            9 :       TyTy::BaseType *cloned_target = target_adt->clone ();
    2690            9 :       cloned_target->set_ref (t_tyvar.get_ref ());
    2691            9 :       Analysis::NodeMapping pseudo_mapping (
    2692            9 :         ctx->get_mappings ().get_current_crate (), 0, t_tyvar.get_ref (), 0);
    2693            9 :       ctx->get_tyctx ()->insert_type (pseudo_mapping, cloned_target);
    2694              : 
    2695            9 :       const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
    2696            9 :                                    t_tyvar, Mutability::Imm);
    2697              : 
    2698            9 :       tree fat_pointer = TyTyResolveCompile::compile (ctx, &r);
    2699            9 :       rust_assert (fat_pointer != error_mark_node);
    2700            9 :       tree data_ptr = address_expression (expression, locus);
    2701              : 
    2702            9 :       size_t tail_idx = source_adt->get_variants ().front ()->num_fields () - 1;
    2703            9 :       tree tail_expr
    2704            9 :         = Backend::struct_field_expression (expression, tail_idx, locus);
    2705              : 
    2706            9 :       auto s_tail_ty = source_adt->get_variants ()
    2707            9 :                          .front ()
    2708              :                          ->get_field_at_index (tail_idx)
    2709            9 :                          ->get_field_type ();
    2710            9 :       auto t_tail_ty = target_adt->get_variants ()
    2711            9 :                          .front ()
    2712              :                          ->get_field_at_index (tail_idx)
    2713            9 :                          ->get_field_type ();
    2714              : 
    2715            9 :       Resolver::Adjustment tail_adj (
    2716            9 :         Resolver::Adjustment::AdjustmentType::UNSIZE, s_tail_ty, t_tail_ty);
    2717            9 :       tree inner_fat_ptr
    2718            9 :         = resolve_unsized_adjustment (tail_adj, tail_expr, locus);
    2719            9 :       rust_assert (inner_fat_ptr != error_mark_node);
    2720            9 :       tree meta = error_mark_node;
    2721            9 :       if (TREE_CODE (inner_fat_ptr) == CONSTRUCTOR)
    2722              :         {
    2723              :           unsigned HOST_WIDE_INT ix;
    2724              :           tree field ATTRIBUTE_UNUSED, val;
    2725           18 :           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (inner_fat_ptr), ix, field,
    2726              :                                     val)
    2727           18 :             if (ix == 1)
    2728              :               {
    2729              :                 meta = val;
    2730              :                 break;
    2731              :               }
    2732              :         }
    2733              :       else
    2734              :         {
    2735            0 :           tree meta_field_decl
    2736            0 :             = DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (inner_fat_ptr)));
    2737            0 :           meta = fold_build3_loc (locus, COMPONENT_REF,
    2738            0 :                                   TREE_TYPE (meta_field_decl), inner_fat_ptr,
    2739              :                                   meta_field_decl, NULL_TREE);
    2740              :         }
    2741              : 
    2742            9 :       std::vector<tree> constructor_elements = {data_ptr, meta};
    2743            9 :       tree result
    2744            9 :         = Backend::constructor_expression (fat_pointer, false,
    2745              :                                            constructor_elements, -1, locus);
    2746            9 :       rust_assert (result != error_mark_node);
    2747            9 :       RS_DST_FLAG (TREE_TYPE (result)) = 1;
    2748            9 :       return result;
    2749            9 :     }
    2750              :   else
    2751              :     {
    2752           11 :       tree target = TyTyResolveCompile::compile (ctx, target_adt);
    2753           11 :       size_t coerce_idx = -1;
    2754           11 :       auto s_variant = source_adt->get_variants ().front ();
    2755           11 :       auto t_variant = target_adt->get_variants ().front ();
    2756              : 
    2757           11 :       for (size_t idx = 0; idx < s_variant->num_fields (); idx++)
    2758              :         {
    2759           11 :           auto s_field_ty
    2760           11 :             = s_variant->get_field_at_index (idx)->get_field_type ();
    2761           11 :           auto t_field_ty
    2762           11 :             = t_variant->get_field_at_index (idx)->get_field_type ();
    2763           11 :           if (!s_field_ty->is_equal (*t_field_ty))
    2764              :             {
    2765           11 :               bool is_phantom = false;
    2766           11 :               if (s_field_ty->is<TyTy::ADTType> ())
    2767           12 :                 if (auto phantom_data
    2768            6 :                     = Analysis::Mappings::get ().lookup_lang_item (
    2769            6 :                       LangItem::Kind::PHANTOM_DATA))
    2770           12 :                   if (s_field_ty->as<TyTy::ADTType> ()->get_id ()
    2771            6 :                       == phantom_data)
    2772            0 :                     is_phantom = true;
    2773              : 
    2774            6 :               if (!is_phantom)
    2775              :                 {
    2776              :                   coerce_idx = idx;
    2777              :                   break;
    2778              :                 }
    2779              :             }
    2780              :         }
    2781           11 :       rust_assert (coerce_idx != (size_t) -1);
    2782           11 :       std::vector<tree> constructor_elements;
    2783           25 :       for (size_t i = 0; i < s_variant->num_fields (); i++)
    2784              :         {
    2785           14 :           tree field_expr
    2786           14 :             = Backend::struct_field_expression (expression, i, locus);
    2787              : 
    2788           14 :           if (i != coerce_idx)
    2789              :             {
    2790            3 :               constructor_elements.push_back (field_expr);
    2791              :             }
    2792              :           else
    2793              :             {
    2794           11 :               auto s_coerce_ty
    2795           11 :                 = s_variant->get_field_at_index (i)->get_field_type ();
    2796           11 :               auto t_coerce_ty
    2797           11 :                 = t_variant->get_field_at_index (i)->get_field_type ();
    2798              : 
    2799           11 :               Resolver::Adjustment adj (adjustment.get_type (), s_coerce_ty,
    2800           11 :                                         t_coerce_ty);
    2801           11 :               tree coerced_inner_expr = error_mark_node;
    2802              : 
    2803           11 :               if (t_coerce_ty->get_kind () == TyTy::TypeKind::SLICE
    2804           11 :                   || t_coerce_ty->get_kind () == TyTy::TypeKind::STR)
    2805            0 :                 coerced_inner_expr
    2806            0 :                   = resolve_unsized_slice_adjustment (adj, field_expr, locus);
    2807           11 :               else if (t_coerce_ty->get_kind () == TyTy::TypeKind::DYNAMIC)
    2808            0 :                 coerced_inner_expr
    2809            0 :                   = resolve_unsized_dyn_adjustment (adj, field_expr, locus);
    2810           11 :               else if (t_coerce_ty->get_kind () == TyTy::TypeKind::ADT)
    2811            6 :                 coerced_inner_expr
    2812            6 :                   = resolve_unsized_adt_adjustment (adj, field_expr, locus);
    2813            5 :               else if (t_coerce_ty->get_kind () == TyTy::TypeKind::POINTER
    2814            5 :                        || t_coerce_ty->get_kind () == TyTy::TypeKind::REF)
    2815              :                 {
    2816            5 :                   bool is_ptr
    2817            5 :                     = t_coerce_ty->get_kind () == TyTy::TypeKind::POINTER;
    2818              : 
    2819            5 :                   TyTy::BaseType *s_base
    2820            5 :                     = is_ptr ? s_coerce_ty->as<TyTy::PointerType> ()
    2821              :                                  ->get_base ()
    2822            5 :                                  ->monomorphized_clone ()
    2823              :                              : s_coerce_ty->as<TyTy::ReferenceType> ()
    2824              :                                  ->get_base ()
    2825            0 :                                  ->monomorphized_clone ();
    2826            5 :                   TyTy::BaseType *t_base
    2827            5 :                     = is_ptr ? t_coerce_ty->as<TyTy::PointerType> ()
    2828              :                                  ->get_base ()
    2829            5 :                                  ->monomorphized_clone ()
    2830              :                              : t_coerce_ty->as<TyTy::ReferenceType> ()
    2831              :                                  ->get_base ()
    2832            0 :                                  ->monomorphized_clone ();
    2833              : 
    2834            5 :                   Resolver::Adjustment::AdjustmentType ref_adj_type
    2835              :                     = Resolver::Adjustment::AdjustmentType::IMM_REF;
    2836              : 
    2837            5 :                   std::vector<Resolver::Adjustment> inner_adjs;
    2838            5 :                   inner_adjs.push_back (Resolver::Adjustment (
    2839              :                     Resolver::Adjustment::AdjustmentType::INDIRECTION,
    2840            5 :                     s_coerce_ty, s_base));
    2841            5 :                   inner_adjs.push_back (Resolver::Adjustment (
    2842              :                     Resolver::Adjustment::AdjustmentType::UNSIZE, s_base,
    2843            5 :                     t_base));
    2844            5 :                   inner_adjs.push_back (
    2845            5 :                     Resolver::Adjustment (ref_adj_type, t_base, t_coerce_ty));
    2846              : 
    2847            5 :                   coerced_inner_expr
    2848            5 :                     = resolve_adjustments (inner_adjs, field_expr, locus);
    2849            5 :                 }
    2850              :               else
    2851            0 :                 rust_unreachable ();
    2852              : 
    2853           11 :               constructor_elements.push_back (coerced_inner_expr);
    2854              :             }
    2855              :         }
    2856              : 
    2857           11 :       return Backend::constructor_expression (target, false,
    2858              :                                               constructor_elements, -1, locus);
    2859           11 :     }
    2860              : 
    2861              :   return error_mark_node;
    2862              : }
    2863              : 
    2864              : tree
    2865          174 : HIRCompileBase::resolve_unsized_dyn_adjustment (
    2866              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2867              : {
    2868          174 :   tree rvalue = expression;
    2869          174 :   location_t rvalue_locus = locus;
    2870              : 
    2871          174 :   auto actual = adjustment.get_actual ();
    2872          174 :   auto expected = adjustment.get_expected ();
    2873              : 
    2874          174 :   const auto dyn = static_cast<const TyTy::DynamicObjectType *> (expected);
    2875              : 
    2876          174 :   rust_debug ("resolve_unsized_dyn_adjustment actual={%s} dyn={%s}",
    2877              :               actual->debug_str ().c_str (), dyn->debug_str ().c_str ());
    2878              : 
    2879          174 :   return coerce_to_dyn_object (rvalue, actual, dyn, rvalue_locus);
    2880              : }
    2881              : 
    2882              : void
    2883           73 : CompileExpr::visit (HIR::RangeFromToExpr &expr)
    2884              : {
    2885           73 :   tree from = CompileExpr::Compile (expr.get_from_expr (), ctx);
    2886           73 :   tree to = CompileExpr::Compile (expr.get_to_expr (), ctx);
    2887           73 :   if (from == error_mark_node || to == error_mark_node)
    2888              :     {
    2889            0 :       translated = error_mark_node;
    2890            0 :       return;
    2891              :     }
    2892              : 
    2893           73 :   TyTy::BaseType *tyty = nullptr;
    2894           73 :   bool ok
    2895           73 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2896           73 :   rust_assert (ok);
    2897              : 
    2898           73 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2899              : 
    2900              :   // make the constructor
    2901           73 :   translated = Backend::constructor_expression (adt, false, {from, to}, -1,
    2902              :                                                 expr.get_locus ());
    2903              : }
    2904              : 
    2905              : void
    2906            7 : CompileExpr::visit (HIR::RangeFromExpr &expr)
    2907              : {
    2908            7 :   tree from = CompileExpr::Compile (expr.get_from_expr (), ctx);
    2909            7 :   if (from == error_mark_node)
    2910              :     {
    2911            0 :       translated = error_mark_node;
    2912            0 :       return;
    2913              :     }
    2914              : 
    2915            7 :   TyTy::BaseType *tyty = nullptr;
    2916            7 :   bool ok
    2917            7 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2918            7 :   rust_assert (ok);
    2919              : 
    2920            7 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2921              : 
    2922              :   // make the constructor
    2923            7 :   translated = Backend::constructor_expression (adt, false, {from}, -1,
    2924              :                                                 expr.get_locus ());
    2925              : }
    2926              : 
    2927              : void
    2928            7 : CompileExpr::visit (HIR::RangeToExpr &expr)
    2929              : {
    2930            7 :   tree to = CompileExpr::Compile (expr.get_to_expr (), ctx);
    2931            7 :   if (to == error_mark_node)
    2932              :     {
    2933            0 :       translated = error_mark_node;
    2934            0 :       return;
    2935              :     }
    2936              : 
    2937            7 :   TyTy::BaseType *tyty = nullptr;
    2938            7 :   bool ok
    2939            7 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2940            7 :   rust_assert (ok);
    2941              : 
    2942            7 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2943              : 
    2944              :   // make the constructor
    2945            7 :   translated
    2946            7 :     = Backend::constructor_expression (adt, false, {to}, -1, expr.get_locus ());
    2947              : }
    2948              : 
    2949              : void
    2950            0 : CompileExpr::visit (HIR::RangeFullExpr &expr)
    2951              : {
    2952            0 :   TyTy::BaseType *tyty = nullptr;
    2953            0 :   bool ok
    2954            0 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2955            0 :   rust_assert (ok);
    2956              : 
    2957            0 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2958            0 :   translated
    2959            0 :     = Backend::constructor_expression (adt, false, {}, -1, expr.get_locus ());
    2960            0 : }
    2961              : 
    2962              : void
    2963          293 : CompileExpr::visit (HIR::ArrayIndexExpr &expr)
    2964              : {
    2965          293 :   tree array_reference = CompileExpr::Compile (expr.get_array_expr (), ctx);
    2966          293 :   tree index = CompileExpr::Compile (expr.get_index_expr (), ctx);
    2967              : 
    2968              :   // this might be an core::ops::index lang item situation
    2969          293 :   TyTy::FnType *fntype;
    2970          293 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    2971          293 :     expr.get_mappings ().get_hirid (), &fntype);
    2972          293 :   if (is_op_overload)
    2973              :     {
    2974           66 :       auto lang_item_type = LangItem::Kind::INDEX;
    2975           66 :       tree operator_overload_call
    2976           66 :         = resolve_operator_overload (lang_item_type, expr, array_reference,
    2977              :                                      index, expr.get_array_expr (),
    2978           66 :                                      expr.get_index_expr ());
    2979              : 
    2980           66 :       tree actual_type = TREE_TYPE (operator_overload_call);
    2981           66 :       bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type);
    2982           66 :       if (!can_indirect)
    2983              :         {
    2984              :           // nothing to do
    2985              :           translated = operator_overload_call;
    2986           66 :           return;
    2987              :         }
    2988              : 
    2989              :       // rust deref always returns a reference from this overload then we can
    2990              :       // actually do the indirection
    2991           31 :       translated
    2992           31 :         = indirect_expression (operator_overload_call, expr.get_locus ());
    2993           31 :       return;
    2994              :     }
    2995              : 
    2996              :   // lets check if the array is a reference type then we can add an
    2997              :   // indirection if required
    2998          227 :   TyTy::BaseType *array_expr_ty = nullptr;
    2999          227 :   bool ok = ctx->get_tyctx ()->lookup_type (
    3000          227 :     expr.get_array_expr ().get_mappings ().get_hirid (), &array_expr_ty);
    3001          227 :   rust_assert (ok);
    3002              : 
    3003              :   // do we need to add an indirect reference
    3004          227 :   if (array_expr_ty->get_kind () == TyTy::TypeKind::REF)
    3005              :     {
    3006           15 :       array_reference
    3007           15 :         = indirect_expression (array_reference, expr.get_locus ());
    3008              :     }
    3009          212 :   else if (TyTy::try_get_box_inner_type (array_expr_ty))
    3010              :     {
    3011            3 :       array_reference
    3012            3 :         = build_box_inner_ptr (array_reference, expr.get_locus ());
    3013            3 :       array_reference
    3014            3 :         = indirect_expression (array_reference, expr.get_locus ());
    3015              :     }
    3016              : 
    3017          227 :   translated = Backend::array_index_expression (array_reference, index,
    3018              :                                                 expr.get_locus ());
    3019              : }
    3020              : 
    3021              : void
    3022           61 : CompileExpr::visit (HIR::ClosureExpr &expr)
    3023              : {
    3024           61 :   TyTy::BaseType *closure_expr_ty = nullptr;
    3025           61 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    3026              :                                        &closure_expr_ty))
    3027              :     {
    3028            0 :       rust_fatal_error (expr.get_locus (),
    3029              :                         "did not resolve type for this ClosureExpr");
    3030              :       return;
    3031              :     }
    3032           61 :   rust_assert (closure_expr_ty->get_kind () == TyTy::TypeKind::CLOSURE);
    3033           61 :   TyTy::ClosureType *closure_tyty
    3034              :     = static_cast<TyTy::ClosureType *> (closure_expr_ty);
    3035           61 :   tree compiled_closure_tyty = TyTyResolveCompile::compile (ctx, closure_tyty);
    3036              : 
    3037              :   // generate closure function
    3038           61 :   generate_closure_function (expr, *closure_tyty, compiled_closure_tyty);
    3039              : 
    3040              :   // lets ignore state capture for now we need to instantiate the struct anyway
    3041              :   // then generate the function
    3042           61 :   std::vector<tree> vals;
    3043           82 :   for (const auto &capture : closure_tyty->get_captures ())
    3044              :     {
    3045              :       // lookup the HirId
    3046           21 :       if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture))
    3047              :         {
    3048              :           // lookup the var decl
    3049           21 :           Bvariable *var = nullptr;
    3050           21 :           bool found = ctx->lookup_var_decl (*hid, &var);
    3051           21 :           rust_assert (found);
    3052              : 
    3053              :           // FIXME
    3054              :           // this should bes based on the closure move-ability
    3055           21 :           tree var_expr = var->get_tree (expr.get_locus ());
    3056           21 :           tree val = address_expression (var_expr, expr.get_locus ());
    3057           21 :           vals.push_back (val);
    3058              :         }
    3059              :       else
    3060            0 :         rust_unreachable ();
    3061              :     }
    3062              : 
    3063           61 :   translated = Backend::constructor_expression (compiled_closure_tyty, false,
    3064              :                                                 vals, -1, expr.get_locus ());
    3065           61 : }
    3066              : 
    3067              : tree
    3068           61 : CompileExpr::generate_closure_function (HIR::ClosureExpr &expr,
    3069              :                                         TyTy::ClosureType &closure_tyty,
    3070              :                                         tree compiled_closure_tyty)
    3071              : {
    3072           61 :   TyTy::FnType *fn_tyty = nullptr;
    3073           61 :   tree compiled_fn_type
    3074           61 :     = generate_closure_fntype (expr, closure_tyty, compiled_closure_tyty,
    3075              :                                &fn_tyty);
    3076           61 :   if (compiled_fn_type == error_mark_node)
    3077              :     return error_mark_node;
    3078              : 
    3079           61 :   const Resolver::CanonicalPath &parent_canonical_path
    3080           61 :     = closure_tyty.get_ident ().path;
    3081              : 
    3082           61 :   tl::optional<NodeId> nid = ctx->get_mappings ().lookup_hir_to_node (
    3083           61 :     expr.get_mappings ().get_hirid ());
    3084           61 :   rust_assert (nid.has_value ());
    3085           61 :   auto node_id = nid.value ();
    3086              : 
    3087           61 :   Resolver::CanonicalPath path = parent_canonical_path.append (
    3088           61 :     Resolver::CanonicalPath::new_seg (node_id, "{{closure}}"));
    3089              : 
    3090           61 :   std::string ir_symbol_name = path.get ();
    3091           61 :   std::string asm_name = ctx->mangle_item (&closure_tyty, path);
    3092              : 
    3093           61 :   unsigned int flags = 0;
    3094           61 :   tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name,
    3095              :                                    flags, expr.get_locus ());
    3096              : 
    3097              :   // insert into the context
    3098           61 :   ctx->insert_function_decl (fn_tyty, fndecl);
    3099           61 :   ctx->insert_closure_decl (&closure_tyty, fndecl);
    3100              : 
    3101              :   // setup the parameters
    3102           61 :   std::vector<Bvariable *> param_vars;
    3103              : 
    3104              :   // closure self
    3105           61 :   Bvariable *self_param
    3106           61 :     = Backend::parameter_variable (fndecl, "$closure", compiled_closure_tyty,
    3107           61 :                                    expr.get_locus ());
    3108           61 :   DECL_ARTIFICIAL (self_param->get_decl ()) = 1;
    3109           61 :   param_vars.push_back (self_param);
    3110              : 
    3111              :   // push a new context
    3112           61 :   ctx->push_closure_context (expr.get_mappings ().get_hirid ());
    3113              : 
    3114              :   // setup the implicit argument captures
    3115           61 :   size_t idx = 0;
    3116           82 :   for (const auto &capture : closure_tyty.get_captures ())
    3117              :     {
    3118              :       // lookup the HirId
    3119           21 :       if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture))
    3120              :         {
    3121              :           // get the assessor
    3122           21 :           tree binding = Backend::struct_field_expression (
    3123              :             self_param->get_tree (expr.get_locus ()), idx, expr.get_locus ());
    3124           21 :           tree indirection = indirect_expression (binding, expr.get_locus ());
    3125              : 
    3126              :           // insert bindings
    3127           21 :           ctx->insert_closure_binding (*hid, indirection);
    3128              : 
    3129              :           // continue
    3130           21 :           idx++;
    3131              :         }
    3132              :       else
    3133            0 :         rust_unreachable ();
    3134              :     }
    3135              : 
    3136              :   // args tuple
    3137           61 :   tree args_type
    3138           61 :     = TyTyResolveCompile::compile (ctx, &closure_tyty.get_parameters ());
    3139           61 :   Bvariable *args_param
    3140           61 :     = Backend::parameter_variable (fndecl, "args", args_type,
    3141           61 :                                    expr.get_locus ());
    3142           61 :   param_vars.push_back (args_param);
    3143              : 
    3144              :   // setup the implicit mappings for the arguments. Since argument passing to
    3145              :   // closure functions is done via passing a tuple but the closure body expects
    3146              :   // just normal arguments this means we need to destructure them similar to
    3147              :   // what we do in MatchExpr's. This means when we have a closure-param of a we
    3148              :   // actually setup the destructure to take from the args tuple
    3149              : 
    3150           61 :   tree args_param_expr = args_param->get_tree (expr.get_locus ());
    3151           61 :   size_t i = 0;
    3152          120 :   for (auto &closure_param : expr.get_params ())
    3153              :     {
    3154           59 :       tree compiled_param_var
    3155           59 :         = Backend::struct_field_expression (args_param_expr, i,
    3156              :                                             closure_param.get_locus ());
    3157              : 
    3158           59 :       CompilePatternBindings::Compile (closure_param.get_pattern (),
    3159              :                                        compiled_param_var, ctx);
    3160           59 :       i++;
    3161              :     }
    3162              : 
    3163           61 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    3164              :     {
    3165            0 :       ctx->pop_closure_context ();
    3166            0 :       return error_mark_node;
    3167              :     }
    3168              : 
    3169              :   // lookup locals
    3170           61 :   HIR::Expr &function_body = expr.get_expr ();
    3171           61 :   bool is_block_expr
    3172           61 :     = function_body.get_expression_type () == HIR::Expr::ExprType::Block;
    3173              : 
    3174           61 :   if (is_block_expr)
    3175              :     {
    3176           52 :       auto body_mappings = function_body.get_mappings ();
    3177           52 :       auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    3178              : 
    3179           52 :       auto candidate
    3180           52 :         = nr_ctx.get_underlying ().values.to_rib (body_mappings.get_nodeid ());
    3181              : 
    3182           52 :       rust_assert (candidate.has_value ());
    3183              :     }
    3184              : 
    3185           61 :   tree enclosing_scope = NULL_TREE;
    3186           61 :   location_t start_location = function_body.get_locus ();
    3187           61 :   location_t end_location = function_body.get_locus ();
    3188           61 :   if (is_block_expr)
    3189              :     {
    3190           52 :       auto &body = static_cast<HIR::BlockExpr &> (function_body);
    3191           52 :       start_location = body.get_locus ();
    3192           52 :       end_location = body.get_end_locus ();
    3193              :     }
    3194              : 
    3195           61 :   tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
    3196              :                                     start_location, end_location);
    3197           61 :   ctx->push_block (code_block);
    3198              : 
    3199           61 :   TyTy::BaseType *tyret = &closure_tyty.get_result_type ();
    3200           61 :   Bvariable *return_address = nullptr;
    3201              : 
    3202           61 :   tree return_type = TyTyResolveCompile::compile (ctx, tyret);
    3203           61 :   bool address_is_taken = false;
    3204           61 :   tree ret_var_stmt = NULL_TREE;
    3205              : 
    3206           61 :   return_address
    3207           61 :     = Backend::temporary_variable (fndecl, code_block, return_type, NULL,
    3208              :                                    address_is_taken, expr.get_locus (),
    3209              :                                    &ret_var_stmt);
    3210              : 
    3211           61 :   ctx->add_statement (ret_var_stmt);
    3212              : 
    3213           61 :   ctx->push_fn (fndecl, return_address, tyret);
    3214              : 
    3215           61 :   if (is_block_expr)
    3216              :     {
    3217           52 :       auto &body = static_cast<HIR::BlockExpr &> (function_body);
    3218           52 :       compile_function_body (fndecl, body, tyret);
    3219              :     }
    3220              :   else
    3221              :     {
    3222            9 :       tree value = CompileExpr::Compile (function_body, ctx);
    3223            9 :       tree return_expr
    3224            9 :         = Backend::return_statement (fndecl, value, function_body.get_locus ());
    3225            9 :       ctx->add_statement (return_expr);
    3226              :     }
    3227              : 
    3228           61 :   tree cleanup = CompileDrop (ctx).build_current_scope_drop_cleanup ();
    3229           61 :   tree bind_tree
    3230           61 :     = ctx->pop_block_with_cleanup (cleanup, function_body.get_locus ());
    3231              : 
    3232           61 :   gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
    3233           61 :   DECL_SAVED_TREE (fndecl) = bind_tree;
    3234              : 
    3235           61 :   ctx->pop_closure_context ();
    3236           61 :   ctx->pop_fn ();
    3237           61 :   ctx->push_function (fndecl);
    3238              : 
    3239           61 :   return fndecl;
    3240           61 : }
    3241              : 
    3242              : tree
    3243           61 : CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
    3244              :                                       const TyTy::ClosureType &closure_tyty,
    3245              :                                       tree compiled_closure_tyty,
    3246              :                                       TyTy::FnType **fn_tyty)
    3247              : {
    3248              :   // grab the specified_bound
    3249           61 :   rust_assert (closure_tyty.num_specified_bounds () == 1);
    3250           61 :   const TyTy::TypeBoundPredicate &predicate
    3251           61 :     = *closure_tyty.get_specified_bounds ().begin ();
    3252              : 
    3253              :   // FnOnce::Output is normalized on demand by normalize_projection's closure
    3254              :   // special-case
    3255              : 
    3256              :   // the function signature is based on the trait bound that the closure
    3257              :   // implements which is determined at the type resolution time
    3258              :   //
    3259              :   // https://github.com/rust-lang/rust/blob/7807a694c2f079fd3f395821bcc357eee8650071/library/core/src/ops/function.rs#L54-L71
    3260              : 
    3261           61 :   TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error ();
    3262           61 :   if (predicate.get_name ().compare ("FnOnce") == 0)
    3263              :     {
    3264          122 :       item = predicate.lookup_associated_item ("call_once").value ();
    3265              :     }
    3266            0 :   else if (predicate.get_name ().compare ("FnMut") == 0)
    3267              :     {
    3268            0 :       item = predicate.lookup_associated_item ("call_mut").value ();
    3269              :     }
    3270            0 :   else if (predicate.get_name ().compare ("Fn") == 0)
    3271              :     {
    3272            0 :       item = predicate.lookup_associated_item ("call").value ();
    3273              :     }
    3274              :   else
    3275              :     {
    3276              :       // FIXME error message?
    3277            0 :       rust_unreachable ();
    3278              :       return error_mark_node;
    3279              :     }
    3280              : 
    3281           61 :   rust_assert (!item.is_error ());
    3282              : 
    3283           61 :   TyTy::BaseType *item_tyty = item.get_tyty_for_receiver (&closure_tyty);
    3284           61 :   rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
    3285           61 :   *fn_tyty = static_cast<TyTy::FnType *> (item_tyty);
    3286           61 :   return TyTyResolveCompile::compile (ctx, item_tyty);
    3287           61 : }
    3288              : 
    3289              : bool
    3290        11419 : CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
    3291              :                                               tree receiver, tree *result)
    3292              : {
    3293        11419 :   TyTy::FnType *fn_sig = nullptr;
    3294        11419 :   bool found_overload = ctx->get_tyctx ()->lookup_operator_overload (
    3295        11419 :     expr.get_mappings ().get_hirid (), &fn_sig);
    3296        11419 :   if (!found_overload)
    3297              :     return false;
    3298              : 
    3299           60 :   auto id = fn_sig->get_ty_ref ();
    3300           60 :   auto dId = fn_sig->get_id ();
    3301              : 
    3302           60 :   tree function = error_mark_node;
    3303           60 :   bool found_closure = ctx->lookup_function_decl (id, &function, dId, fn_sig);
    3304           60 :   if (!found_closure)
    3305              :     {
    3306              :       // something went wrong we still return true as this was meant to be an fn
    3307              :       // trait call
    3308            0 :       *result = error_mark_node;
    3309            0 :       return true;
    3310              :     }
    3311              : 
    3312              :   // need to apply any autoderef's to the self argument
    3313           60 :   HIR::Expr &fnexpr = expr.get_fnexpr ();
    3314           60 :   HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
    3315           60 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    3316           60 :   bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
    3317              :                                                           &adjustments);
    3318           60 :   rust_assert (ok);
    3319              : 
    3320              :   // apply adjustments for the fn call
    3321           60 :   tree self = resolve_adjustments (*adjustments, receiver, expr.get_locus ());
    3322              : 
    3323              :   // resolve the arguments
    3324           60 :   std::vector<tree> tuple_arg_vals;
    3325          120 :   for (auto &argument : expr.get_arguments ())
    3326              :     {
    3327           60 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    3328           60 :       tuple_arg_vals.push_back (rvalue);
    3329              :     }
    3330              : 
    3331              :   // this is always the 2nd argument in the function signature
    3332           60 :   tree fnty = TREE_TYPE (function);
    3333           60 :   tree fn_arg_tys = TYPE_ARG_TYPES (fnty);
    3334           60 :   tree tuple_args_tyty_chain = TREE_CHAIN (fn_arg_tys);
    3335           60 :   tree tuple_args_tyty = TREE_VALUE (tuple_args_tyty_chain);
    3336              : 
    3337           60 :   tree tuple_args
    3338           60 :     = Backend::constructor_expression (tuple_args_tyty, false, tuple_arg_vals,
    3339           60 :                                        -1, expr.get_locus ());
    3340              : 
    3341              :   // args are always self, and the tuple of the args we are passing where
    3342              :   // self is the path of the call-expr in this case the fn_address
    3343           60 :   std::vector<tree> args;
    3344           60 :   args.push_back (self);
    3345           60 :   args.push_back (tuple_args);
    3346              : 
    3347           60 :   tree call_address = address_expression (function, expr.get_locus ());
    3348           60 :   *result
    3349           60 :     = Backend::call_expression (call_address, args, nullptr /* static chain ?*/,
    3350              :                                 expr.get_locus ());
    3351           60 :   return true;
    3352           60 : }
    3353              : 
    3354              : tree
    3355            3 : CompileExpr::construct_block_label (HIR::BlockExpr &expr)
    3356              : {
    3357            3 :   if (expr.has_label ())
    3358              :     {
    3359            3 :       fncontext fnctx = ctx->peek_fn ();
    3360            3 :       HIR::LoopLabel &label = expr.get_label ();
    3361            3 :       std::string label_name = label.get_lifetime ().get_name ();
    3362            3 :       HirId label_id = label.get_lifetime ().get_mappings ().get_hirid ();
    3363            3 :       tree label_decl
    3364            3 :         = Backend::label (fnctx.fndecl, label_name, label.get_locus ());
    3365            3 :       tree label_expr = Backend::label_definition_statement (label_decl);
    3366            3 :       ctx->insert_break_label (label_id, label_decl);
    3367            3 :       return label_expr;
    3368            3 :     }
    3369              :   return NULL_TREE;
    3370              : }
    3371              : 
    3372              : tree
    3373            0 : CompileExpr::lookup_label (NodeId to_be_resolved)
    3374              : {
    3375            0 :   HirId ref = resolve_nodeid (to_be_resolved, Resolver2_0::Namespace::Labels);
    3376            0 :   tree label = NULL_TREE;
    3377            0 :   rust_assert (ctx->lookup_label_decl (ref, &label)
    3378              :                && "failed to lookup a label");
    3379            0 :   return label;
    3380              : }
    3381              : 
    3382              : Bvariable *
    3383            5 : CompileExpr::lookup_label_temp_var (NodeId to_be_resolved)
    3384              : {
    3385              :   // TODO: Not sure that this temp var should have been inserted in the Labels
    3386              :   // namespace? Why not values?
    3387            5 :   HirId ref = resolve_nodeid (to_be_resolved, Resolver2_0::Namespace::Labels);
    3388            5 :   Bvariable *ltemp = nullptr;
    3389            5 :   rust_assert (ctx->lookup_var_decl (ref, &ltemp)
    3390              :                && "failed to lookup a temp var");
    3391            5 :   return ltemp;
    3392              : }
    3393              : 
    3394              : HirId
    3395           10 : CompileExpr::resolve_nodeid (NodeId to_be_resolved, Resolver2_0::Namespace ns)
    3396              : {
    3397           10 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    3398              : 
    3399           10 :   NodeId resolved_node_id;
    3400           10 :   resolved_node_id = nr_ctx.lookup (to_be_resolved, ns).value ();
    3401              : 
    3402           10 :   HirId ref
    3403           10 :     = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id).value ();
    3404           10 :   return ref;
    3405              : }
    3406              : 
    3407              : std::pair<tree, tree>
    3408          244 : CompileExpr::construct_loop_labels (tl::optional<HIR::LoopLabel> opt_loop_label)
    3409              : {
    3410          244 :   fncontext fnctx = ctx->peek_fn ();
    3411          244 :   tree break_label_decl = NULL_TREE;
    3412          244 :   tree break_label_expr = NULL_TREE;
    3413          244 :   tree continue_label_decl = NULL_TREE;
    3414          244 :   tree continue_label_expr = NULL_TREE;
    3415          244 :   location_t label_locus = UNKNOWN_LOCATION;
    3416          244 :   tl::optional<std::string> continue_label_name = tl::nullopt;
    3417          244 :   tl::optional<std::string> break_label_name = tl::nullopt;
    3418          244 :   tl::optional<HirId> label_hirid = tl::nullopt;
    3419          244 :   if (opt_loop_label.has_value ())
    3420              :     {
    3421           51 :       label_locus = opt_loop_label.value ().get_locus ();
    3422           51 :       HIR::LoopLabel &loop_label = opt_loop_label.value ();
    3423           51 :       std::string label_name = loop_label.get_lifetime ().get_name ();
    3424           51 :       continue_label_name = label_name + "_continue";
    3425           51 :       break_label_name = label_name + "_break";
    3426           51 :       label_hirid = loop_label.get_lifetime ().get_mappings ().get_hirid ();
    3427           51 :     }
    3428          244 :   continue_label_decl
    3429          244 :     = Backend::label (fnctx.fndecl, continue_label_name, label_locus);
    3430          244 :   continue_label_expr
    3431          244 :     = Backend::label_definition_statement (continue_label_decl);
    3432          244 :   break_label_decl
    3433          244 :     = Backend::label (fnctx.fndecl, break_label_name, label_locus);
    3434          244 :   break_label_expr = Backend::label_definition_statement (break_label_decl);
    3435          244 :   if (label_hirid.has_value ())
    3436              :     {
    3437           51 :       ctx->insert_continue_label (label_hirid.value (), continue_label_decl);
    3438           51 :       ctx->insert_break_label (label_hirid.value (), break_label_decl);
    3439              :     }
    3440          244 :   ctx->push_loop_begin_label (continue_label_decl);
    3441          244 :   ctx->push_loop_end_label (break_label_decl);
    3442          244 :   return std::make_pair (continue_label_expr, break_label_expr);
    3443          244 : }
    3444              : 
    3445              : } // namespace Compile
    3446              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

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