LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors/borrowck - rust-bir-builder-expr-stmt.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 38.9 % 378 147
Test Date: 2026-02-28 14:20:25 Functions: 26.4 % 53 14
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
      17              : // not see
      18              : // <http://www.gnu.org/licenses/>.
      19              : 
      20              : #include "rust-bir-builder-expr-stmt.h"
      21              : #include "rust-bir-builder-lazyboolexpr.h"
      22              : #include "rust-bir-builder-pattern.h"
      23              : #include "rust-bir-builder-struct.h"
      24              : #include "rust-hir-expr.h"
      25              : 
      26              : namespace Rust {
      27              : namespace BIR {
      28              : 
      29              : using LoopAndLabelCtx = BuilderContext::LoopAndLabelCtx;
      30              : 
      31              : BuilderContext::LoopAndLabelCtx &
      32            0 : ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr)
      33              : {
      34            0 :   NodeId label
      35            0 :     = (expr.has_loop_label ())
      36            0 :         ? expr.get_loop_label ().get_lifetime ().get_mappings ().get_nodeid ()
      37            0 :         : UNKNOWN_NODEID;
      38            0 :   PlaceId label_var = take_or_create_return_place (lookup_type (expr));
      39              : 
      40            0 :   BasicBlockId continue_bb = new_bb ();
      41            0 :   push_goto (continue_bb);
      42            0 :   ctx.current_bb = continue_bb;
      43              :   // falseUnwind
      44            0 :   start_new_consecutive_bb ();
      45              : 
      46            0 :   BasicBlockId break_bb = new_bb ();
      47              :   // We are still outside the loop block;
      48            0 :   ScopeId continue_scope
      49            0 :     = ctx.place_db.get_current_scope_id ().next_scope_id ();
      50            0 :   ctx.loop_and_label_stack.emplace_back (true, label, label_var, break_bb,
      51              :                                          continue_bb, continue_scope);
      52              : 
      53            0 :   return ctx.loop_and_label_stack.back ();
      54              : }
      55              : 
      56              : BuilderContext::LoopAndLabelCtx &
      57            0 : ExprStmtBuilder::get_label_ctx (HIR::Lifetime &label)
      58              : {
      59            0 :   NodeId label_id = resolve_label (label);
      60            0 :   auto lookup = std::find_if (ctx.loop_and_label_stack.rbegin (),
      61            0 :                               ctx.loop_and_label_stack.rend (),
      62            0 :                               [label_id] (LoopAndLabelCtx &info) {
      63            0 :                                 return info.label == label_id;
      64            0 :                               });
      65            0 :   rust_assert (lookup != ctx.loop_and_label_stack.rend ());
      66            0 :   return *lookup;
      67              : }
      68              : 
      69              : LoopAndLabelCtx &
      70            0 : ExprStmtBuilder::get_unnamed_loop_ctx ()
      71              : {
      72            0 :   auto lookup
      73            0 :     = std::find_if (ctx.loop_and_label_stack.rbegin (),
      74            0 :                     ctx.loop_and_label_stack.rend (),
      75            0 :                     [] (LoopAndLabelCtx &info) { return info.is_loop; });
      76            0 :   rust_assert (lookup != ctx.loop_and_label_stack.rend ());
      77            0 :   return *lookup;
      78              : }
      79              : 
      80              : void
      81            0 : ExprStmtBuilder::visit (HIR::ClosureExpr &expr)
      82              : {
      83            0 :   auto closure_ty = lookup_type (expr)->as<TyTy::ClosureType> ();
      84            0 :   std::vector<PlaceId> captures;
      85            0 :   std::vector<location_t> capture_locations;
      86            0 :   for (auto &capture : closure_ty->get_captures ())
      87              :     {
      88            0 :       captures.push_back (ctx.place_db.lookup_variable (capture));
      89            0 :       auto location = Analysis::Mappings::get ()
      90            0 :                         .lookup_ast_item (capture)
      91            0 :                         .value ()
      92            0 :                         ->get_locus ();
      93            0 :       capture_locations.push_back (location);
      94              :     }
      95            0 :   move_all (captures, capture_locations);
      96              : 
      97              :   // Note: Not a coercion site for captures.
      98            0 :   return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr),
      99              :                expr.get_locus ());
     100            0 : }
     101              : 
     102              : void
     103            6 : ExprStmtBuilder::visit (HIR::StructExprStructFields &fields)
     104              : {
     105            6 :   auto *p_adt_type = lookup_type (fields)->as<TyTy::ADTType> ();
     106            6 :   auto struct_ty = p_adt_type->get_variants ().at (0);
     107            6 :   auto init_values = StructBuilder (ctx, struct_ty).build (fields);
     108              :   // collect fields locations
     109            6 :   std::vector<location_t> field_locations;
     110           12 :   for (auto &field : fields.get_fields ())
     111              :     {
     112            6 :       field_locations.push_back (field->get_locus ());
     113              :     }
     114            6 :   move_all (init_values, field_locations);
     115            6 :   return_expr (new InitializerExpr (std::move (init_values)),
     116              :                lookup_type (fields), fields.get_locus ());
     117            6 : }
     118              : 
     119              : void
     120            0 : ExprStmtBuilder::visit (HIR::StructExprStruct &expr)
     121              : {
     122              :   // There is no way to modify empty struct, which makes them constant.
     123            0 :   return_place (ctx.place_db.get_constant (lookup_type (expr)),
     124              :                 expr.get_locus ());
     125            0 : }
     126              : 
     127              : void
     128           34 : ExprStmtBuilder::visit (HIR::LiteralExpr &expr)
     129              : {
     130              :   // Different literal values of the same type are not distinguished in BIR.
     131           34 :   return_place (ctx.place_db.get_constant (lookup_type (expr)),
     132              :                 expr.get_locus ());
     133           34 : }
     134              : 
     135              : void
     136           42 : ExprStmtBuilder::visit (HIR::BorrowExpr &expr)
     137              : {
     138           42 :   auto operand = visit_expr (expr.get_expr ());
     139           42 :   if (ctx.place_db[operand].is_constant ())
     140              :     {
     141              :       // Cannot borrow a constant, must create a temporary copy.
     142            1 :       push_tmp_assignment (operand, expr.get_locus ());
     143            1 :       operand = translated;
     144              :     }
     145              : 
     146              :   // BorrowExpr cannot be annotated with lifetime.
     147           42 :   return_borrowed (operand, lookup_type (expr), expr.get_locus ());
     148           42 : }
     149              : 
     150              : void
     151           10 : ExprStmtBuilder::visit (HIR::DereferenceExpr &expr)
     152              : {
     153           10 :   auto operand = visit_expr (expr.get_expr ());
     154           10 :   return_place (ctx.place_db.lookup_or_add_path (Place::DEREF,
     155              :                                                  lookup_type (expr), operand),
     156              :                 expr.get_locus ());
     157           10 : }
     158              : 
     159              : void
     160            0 : ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr)
     161              : {
     162              :   // TODO: desugar in AST->HIR
     163            0 :   rust_sorry_at (expr.get_locus (), "error propagation is not supported");
     164            0 : }
     165              : 
     166              : void
     167            0 : ExprStmtBuilder::visit (HIR::NegationExpr &expr)
     168              : {
     169            0 :   PlaceId operand = visit_expr (expr.get_expr ());
     170            0 :   return_expr (new Operator<1> (
     171            0 :                  {move_place (operand, expr.get_expr ().get_locus ())}),
     172              :                lookup_type (expr), expr.get_locus ());
     173            0 : }
     174              : 
     175              : void
     176            0 : ExprStmtBuilder::visit (HIR::ArithmeticOrLogicalExpr &expr)
     177              : {
     178            0 :   PlaceId lhs = visit_expr (expr.get_lhs ());
     179            0 :   PlaceId rhs = visit_expr (expr.get_rhs ());
     180            0 :   return_expr (new Operator<2> (
     181            0 :                  {move_place (lhs, expr.get_lhs ().get_locus ()),
     182            0 :                   move_place (rhs, expr.get_rhs ().get_locus ())}),
     183              :                lookup_type (expr), expr.get_locus ());
     184            0 : }
     185              : 
     186              : void
     187            0 : ExprStmtBuilder::visit (HIR::ComparisonExpr &expr)
     188              : {
     189            0 :   PlaceId lhs = visit_expr (expr.get_lhs ());
     190            0 :   PlaceId rhs = visit_expr (expr.get_rhs ());
     191            0 :   return_expr (new Operator<2> (
     192            0 :                  {move_place (lhs, expr.get_lhs ().get_locus ()),
     193            0 :                   move_place (rhs, expr.get_rhs ().get_locus ())}),
     194              :                lookup_type (expr), expr.get_locus ());
     195            0 : }
     196              : 
     197              : void
     198            0 : ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr)
     199              : {
     200            0 :   return_place (LazyBooleanExprBuilder (ctx, take_or_create_return_place (
     201            0 :                                                lookup_type (expr)))
     202              :                   .build (expr),
     203              :                 expr.get_locus ());
     204            0 : }
     205              : 
     206              : void
     207            0 : ExprStmtBuilder::visit (HIR::TypeCastExpr &expr)
     208              : {
     209            0 :   auto operand = visit_expr (expr.get_expr ());
     210            0 :   return_expr (new Operator<1> ({operand}), lookup_type (expr),
     211              :                expr.get_locus ());
     212            0 : }
     213              : 
     214              : void
     215            5 : ExprStmtBuilder::visit (HIR::AssignmentExpr &expr)
     216              : {
     217            5 :   auto lhs = visit_expr (expr.get_lhs ());
     218            5 :   auto rhs = visit_expr (expr.get_rhs ());
     219            5 :   push_assignment (lhs, rhs, expr.get_locus ());
     220            5 :   translated = INVALID_PLACE;
     221            5 : }
     222              : 
     223              : void
     224            0 : ExprStmtBuilder::visit (HIR::CompoundAssignmentExpr &expr)
     225              : {
     226            0 :   auto lhs = visit_expr (expr.get_lhs ());
     227            0 :   auto rhs = visit_expr (expr.get_rhs ());
     228            0 :   push_assignment (lhs, new Operator<2> ({lhs, rhs}), expr.get_locus ());
     229            0 : }
     230              : 
     231              : void
     232            0 : ExprStmtBuilder::visit (HIR::GroupedExpr &expr)
     233              : {
     234            0 :   return_place (visit_expr (expr.get_expr_in_parens ()), expr.get_locus ());
     235            0 : }
     236              : 
     237              : void
     238            0 : ExprStmtBuilder::visit (HIR::ArrayExpr &expr)
     239              : {
     240            0 :   auto &elems = expr.get_internal_elements ();
     241            0 :   switch (elems.get_array_expr_type ())
     242              :     {
     243            0 :     case HIR::ArrayElems::VALUES:
     244            0 :       {
     245            0 :         auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (elems));
     246            0 :         auto init_values = visit_list (elem_vals.get_values ());
     247              :         // collect locations
     248            0 :         std::vector<location_t> value_locations;
     249            0 :         for (auto &value : elem_vals.get_values ())
     250              :           {
     251            0 :             value_locations.push_back (value->get_locus ());
     252              :           }
     253            0 :         move_all (init_values, value_locations);
     254            0 :         return_expr (new InitializerExpr (std::move (init_values)),
     255              :                      lookup_type (expr), expr.get_locus ());
     256            0 :         break;
     257            0 :       }
     258            0 :     case HIR::ArrayElems::COPIED:
     259            0 :       {
     260            0 :         auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (elems));
     261            0 :         auto init = visit_expr (elem_copied.get_elem_to_copy ());
     262            0 :         return_expr (new InitializerExpr ({init}), lookup_type (expr),
     263              :                      expr.get_locus ());
     264            0 :         break;
     265              :       }
     266              :     }
     267            0 : }
     268              : 
     269              : void
     270            0 : ExprStmtBuilder::visit (HIR::ArrayIndexExpr &expr)
     271              : {
     272            0 :   auto lhs = visit_expr (expr.get_array_expr ());
     273            0 :   auto rhs = visit_expr (expr.get_index_expr ());
     274              :   // The index is not tracked in BIR.
     275            0 :   std::ignore = rhs;
     276            0 :   return_place (ctx.place_db.lookup_or_add_path (Place::INDEX,
     277              :                                                  lookup_type (expr), lhs),
     278              :                 expr.get_locus ());
     279            0 : }
     280              : 
     281              : void
     282            0 : ExprStmtBuilder::visit (HIR::TupleExpr &expr)
     283              : {
     284            0 :   std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ());
     285            0 :   return_expr (new InitializerExpr (std::move (init_values)),
     286              :                lookup_type (expr), expr.get_locus ());
     287            0 : }
     288              : 
     289              : void
     290            0 : ExprStmtBuilder::visit (HIR::TupleIndexExpr &expr)
     291              : {
     292            0 :   auto tuple = visit_expr (expr.get_tuple_expr ());
     293            0 :   return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
     294              :                                                  lookup_type (expr), tuple,
     295            0 :                                                  expr.get_tuple_index ()),
     296              :                 expr.get_locus ());
     297            0 : }
     298              : 
     299              : void
     300           11 : ExprStmtBuilder::visit (HIR::CallExpr &expr)
     301              : {
     302           11 :   PlaceId fn = visit_expr (expr.get_fnexpr ());
     303           11 :   std::vector<PlaceId> arguments = visit_list (expr.get_arguments ());
     304              : 
     305           11 :   const auto fn_type
     306           11 :     = ctx.place_db[fn].tyty->as<const TyTy::CallableTypeInterface> ();
     307              : 
     308           22 :   for (size_t i = 0; i < fn_type->get_num_params (); ++i)
     309              :     {
     310           11 :       coercion_site (arguments[i], fn_type->get_param_type_at (i));
     311              :     }
     312              : 
     313              :   // collect parameter locations
     314           11 :   std::vector<location_t> parameter_locations;
     315           22 :   for (auto &parameter : expr.get_arguments ())
     316              :     {
     317           11 :       parameter_locations.push_back (parameter->get_locus ());
     318              :     }
     319           11 :   move_all (arguments, parameter_locations);
     320              : 
     321           11 :   return_expr (new CallExpr (fn, std::move (arguments)), lookup_type (expr),
     322              :                expr.get_locus (), true);
     323           11 : }
     324              : 
     325              : void
     326            0 : ExprStmtBuilder::visit (HIR::InlineAsm &expr)
     327            0 : {}
     328              : 
     329              : void
     330            0 : ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr)
     331            0 : {}
     332              : 
     333              : void
     334            0 : ExprStmtBuilder::visit (HIR::OffsetOf &expr)
     335            0 : {}
     336              : 
     337              : void
     338            0 : ExprStmtBuilder::visit (HIR::MethodCallExpr &expr)
     339            0 : {}
     340              : 
     341              : void
     342            5 : ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr)
     343              : {
     344            5 :   auto receiver = visit_expr (expr.get_receiver_expr ());
     345            5 :   auto type = autoderef (receiver);
     346            5 :   rust_assert (type->get_kind () == TyTy::ADT);
     347            5 :   auto adt = type->as<TyTy::ADTType> ();
     348            5 :   rust_assert (!adt->is_enum ());
     349            5 :   rust_assert (adt->number_of_variants () == 1);
     350            5 :   auto struct_ty = adt->get_variants ().at (0);
     351              : 
     352            5 :   TyTy::StructFieldType *field_ty = nullptr;
     353            5 :   size_t field_index = 0;
     354            5 :   bool ok = struct_ty->lookup_field (expr.get_field_name ().as_string (),
     355              :                                      &field_ty, &field_index);
     356            5 :   rust_assert (ok);
     357              : 
     358            5 :   return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
     359              :                                                  field_ty->get_field_type (),
     360              :                                                  receiver, field_index),
     361              :                 expr.get_locus ());
     362            5 : }
     363              : 
     364              : void
     365           46 : ExprStmtBuilder::visit (HIR::BlockExpr &block)
     366              : {
     367           46 :   push_new_scope ();
     368              : 
     369           46 :   if (block.has_label ())
     370              :     {
     371            0 :       NodeId label
     372            0 :         = block.get_label ().get_lifetime ().get_mappings ().get_nodeid ();
     373            0 :       PlaceId label_var = take_or_create_return_place (lookup_type (block));
     374            0 :       ctx.loop_and_label_stack.emplace_back (
     375            0 :         false, label, label_var, new_bb (), INVALID_BB,
     376            0 :         ctx.place_db.get_current_scope_id ());
     377              :     }
     378              : 
     379              :   // Eliminates dead code after break, continue, return.
     380           46 :   bool unreachable = false;
     381          164 :   for (auto &stmt : block.get_statements ())
     382              :     {
     383          120 :       stmt->accept_vis (*this);
     384          120 :       if (ctx.get_current_bb ().is_terminated ())
     385              :         {
     386              :           unreachable = true;
     387              :           break;
     388              :         }
     389              :     }
     390              : 
     391           46 :   if (block.has_label ())
     392              :     {
     393            0 :       auto block_ctx = ctx.loop_and_label_stack.back ();
     394            0 :       if (block.has_expr () && !unreachable)
     395              :         {
     396            0 :           push_assignment (block_ctx.label_var,
     397              :                            visit_expr (block.get_final_expr ()),
     398              :                            block.get_start_locus ());
     399              :         }
     400            0 :       if (!ctx.get_current_bb ().is_terminated ())
     401              :         {
     402            0 :           push_goto (block_ctx.break_bb);
     403              :         }
     404            0 :       ctx.current_bb = block_ctx.break_bb;
     405            0 :       ctx.loop_and_label_stack.pop_back ();
     406              : 
     407            0 :       return_place (block_ctx.label_var, block.get_start_locus ());
     408              :     }
     409           46 :   else if (block.has_expr () && !unreachable)
     410              :     {
     411           14 :       return_place (visit_expr (block.get_final_expr (),
     412              :                                 take_or_create_return_place (
     413              :                                   lookup_type (block.get_final_expr ()))),
     414              :                     block.get_start_locus ());
     415              :     }
     416              : 
     417           46 :   if (!unreachable)
     418           44 :     pop_scope ();
     419              :   else
     420            2 :     ctx.place_db.pop_scope ();
     421           46 : }
     422              : 
     423              : void
     424            0 : ExprStmtBuilder::visit (HIR::AnonConst &block)
     425              : {
     426            0 :   rust_unreachable ();
     427              : }
     428              : 
     429              : void
     430            0 : ExprStmtBuilder::visit (HIR::ConstBlock &block)
     431              : {
     432            0 :   rust_unreachable ();
     433              : }
     434              : 
     435              : void
     436            0 : ExprStmtBuilder::visit (HIR::ContinueExpr &cont)
     437              : {
     438            0 :   LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ())
     439            0 :                                            : get_unnamed_loop_ctx ();
     440            0 :   start_new_consecutive_bb ();
     441            0 :   unwind_until (info.continue_scope);
     442            0 :   push_goto (info.continue_bb);
     443              :   // No code allowed after continue. Handled in BlockExpr.
     444            0 : }
     445              : 
     446              : void
     447            0 : ExprStmtBuilder::visit (HIR::BreakExpr &brk)
     448              : {
     449            0 :   LoopAndLabelCtx info = brk.has_label () ? get_label_ctx (brk.get_label ())
     450            0 :                                           : get_unnamed_loop_ctx ();
     451            0 :   if (brk.has_break_expr ())
     452            0 :     push_assignment (info.label_var, visit_expr (brk.get_expr ()),
     453              :                      brk.get_locus ());
     454              : 
     455            0 :   start_new_consecutive_bb ();
     456            0 :   unwind_until (ctx.place_db.get_scope (info.continue_scope).parent);
     457            0 :   push_goto (info.break_bb);
     458              :   // No code allowed after continue. Handled in BlockExpr.
     459            0 : }
     460              : 
     461              : void
     462            0 : ExprStmtBuilder::visit (HIR::RangeFromToExpr &range)
     463              : {
     464            0 :   auto from = visit_expr (range.get_from_expr ());
     465            0 :   auto to = visit_expr (range.get_to_expr ());
     466            0 :   return_expr (new InitializerExpr ({from, to}), lookup_type (range),
     467              :                range.get_locus ());
     468            0 : }
     469              : 
     470              : void
     471            0 : ExprStmtBuilder::visit (HIR::RangeFromExpr &expr)
     472              : {
     473            0 :   auto from = visit_expr (expr.get_from_expr ());
     474            0 :   return_expr (new InitializerExpr ({from}), lookup_type (expr),
     475              :                expr.get_locus ());
     476            0 : }
     477              : 
     478              : void
     479            0 : ExprStmtBuilder::visit (HIR::RangeToExpr &expr)
     480              : {
     481            0 :   auto to = visit_expr (expr.get_to_expr ());
     482            0 :   return_expr (new InitializerExpr ({to}), lookup_type (expr),
     483              :                expr.get_locus ());
     484            0 : }
     485              : 
     486              : void
     487            0 : ExprStmtBuilder::visit (HIR::RangeFullExpr &expr)
     488              : {
     489            0 :   return_expr (new InitializerExpr ({}), lookup_type (expr), expr.get_locus ());
     490            0 : }
     491              : 
     492              : void
     493            0 : ExprStmtBuilder::visit (HIR::RangeFromToInclExpr &expr)
     494              : {
     495            0 :   auto from = visit_expr (expr.get_from_expr ());
     496            0 :   auto to = visit_expr (expr.get_to_expr ());
     497            0 :   return_expr (new InitializerExpr ({from, to}), lookup_type (expr),
     498              :                expr.get_locus ());
     499            0 : }
     500              : 
     501              : void
     502            0 : ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr)
     503              : {
     504            0 :   auto to = visit_expr (expr.get_to_expr ());
     505            0 :   return_expr (new InitializerExpr ({to}), lookup_type (expr),
     506              :                expr.get_locus ());
     507            0 : }
     508              : 
     509              : void
     510            2 : ExprStmtBuilder::visit (HIR::ReturnExpr &ret)
     511              : {
     512            2 :   if (ret.has_return_expr ())
     513              :     {
     514            2 :       push_assignment (RETURN_VALUE_PLACE,
     515              :                        move_place (visit_expr (ret.get_expr ()),
     516            2 :                                    ret.get_expr ().get_locus ()),
     517            2 :                        ret.get_expr ().get_locus ());
     518              :     }
     519            2 :   unwind_until (ROOT_SCOPE);
     520            2 :   push_return (ret.get_locus ());
     521            2 :   translated = INVALID_PLACE;
     522            2 : }
     523              : 
     524              : void
     525            0 : ExprStmtBuilder::visit (HIR::UnsafeBlockExpr &expr)
     526              : {
     527            0 :   rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported");
     528            0 : }
     529              : 
     530              : void
     531            0 : ExprStmtBuilder::visit (HIR::LoopExpr &expr)
     532              : {
     533            0 :   auto loop = setup_loop (expr);
     534              : 
     535            0 :   std::ignore = visit_expr (expr.get_loop_block ());
     536            0 :   if (!ctx.get_current_bb ().is_terminated ())
     537            0 :     push_goto (loop.continue_bb);
     538              : 
     539            0 :   ctx.current_bb = loop.break_bb;
     540            0 : }
     541              : 
     542              : void
     543            0 : ExprStmtBuilder::visit (HIR::WhileLoopExpr &expr)
     544              : {
     545            0 :   auto loop = setup_loop (expr);
     546              : 
     547            0 :   auto cond_val = visit_expr (expr.get_predicate_expr ());
     548            0 :   auto body_bb = new_bb ();
     549            0 :   push_switch (cond_val, expr.get_locus (), {body_bb, loop.break_bb});
     550              : 
     551            0 :   ctx.current_bb = body_bb;
     552            0 :   std::ignore = visit_expr (expr.get_loop_block ());
     553            0 :   push_goto (loop.continue_bb);
     554              : 
     555            0 :   ctx.current_bb = loop.break_bb;
     556            0 : }
     557              : 
     558              : void
     559            0 : ExprStmtBuilder::visit (HIR::WhileLetLoopExpr &expr)
     560              : {
     561              :   // TODO: Desugar in AST->HIR
     562            0 :   rust_sorry_at (expr.get_locus (), "while let loops are not yet supported");
     563            0 : }
     564              : 
     565              : void
     566            4 : ExprStmtBuilder::visit (HIR::IfExpr &expr)
     567              : {
     568              :   // If without else cannot return a non-unit value (see [E0317]).
     569              : 
     570            4 :   if (expr.get_if_block ().statements.empty ())
     571            4 :     return;
     572              : 
     573            4 :   push_switch (visit_expr (expr.get_if_condition ()), expr.get_locus ());
     574            4 :   BasicBlockId if_block = ctx.current_bb;
     575              : 
     576            4 :   ctx.current_bb = new_bb ();
     577            4 :   BasicBlockId then_start_block = ctx.current_bb;
     578            4 :   std::ignore = visit_expr (expr.get_if_block ());
     579            4 :   if (!ctx.get_current_bb ().is_terminated ())
     580            4 :     push_goto (INVALID_BB); // Resolved later.
     581            4 :   BasicBlockId then_end_block = ctx.current_bb;
     582              : 
     583            4 :   ctx.current_bb = new_bb ();
     584            4 :   BasicBlockId final_block = ctx.current_bb;
     585            4 :   return_unit (expr);
     586              : 
     587              :   // Jumps are added at the end to match rustc MIR order for easier comparison.
     588            4 :   add_jump (if_block, then_start_block);
     589            4 :   add_jump (if_block, final_block);
     590              : 
     591            4 :   auto &then_end_bb = ctx.basic_blocks[then_end_block];
     592            4 :   if (then_end_bb.is_goto_terminated () && then_end_bb.successors.empty ())
     593            4 :     add_jump (then_end_block, final_block);
     594              : }
     595              : 
     596              : void
     597            3 : ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
     598              : {
     599            3 :   push_switch (move_place (visit_expr (expr.get_if_condition ()),
     600            3 :                            expr.get_if_condition ().get_locus ()),
     601              :                expr.get_locus ());
     602            3 :   BasicBlockId if_end_bb = ctx.current_bb;
     603              : 
     604            3 :   PlaceId result = take_or_create_return_place (lookup_type (expr));
     605              : 
     606            3 :   ctx.current_bb = new_bb ();
     607            3 :   BasicBlockId then_start_bb = ctx.current_bb;
     608            3 :   std::ignore = visit_expr (expr.get_if_block (), result);
     609            3 :   if (!ctx.get_current_bb ().is_terminated ())
     610            2 :     push_goto (INVALID_BB); // Resolved later.
     611            3 :   BasicBlockId then_end_bb = ctx.current_bb;
     612              : 
     613            3 :   ctx.current_bb = new_bb ();
     614            3 :   BasicBlockId else_start_bb = ctx.current_bb;
     615            3 :   std::ignore = visit_expr (expr.get_else_block (), result);
     616            3 :   if (!ctx.get_current_bb ().is_terminated ())
     617            2 :     push_goto (INVALID_BB); // Resolved later.
     618            3 :   BasicBlockId else_end_bb = ctx.current_bb;
     619              : 
     620            3 :   ctx.current_bb = new_bb ();
     621            3 :   BasicBlockId final_start_bb = ctx.current_bb;
     622            3 :   return_place (result, expr.get_locus ());
     623              : 
     624              :   // Jumps are added at the end to match rustc MIR order for easier comparison.
     625            3 :   add_jump (if_end_bb, then_start_bb);
     626            3 :   add_jump (if_end_bb, else_start_bb);
     627              : 
     628            3 :   auto &then_bb = ctx.basic_blocks[then_end_bb];
     629            3 :   if (then_bb.is_goto_terminated () && then_bb.successors.empty ())
     630            2 :     add_jump (then_end_bb, final_start_bb);
     631              : 
     632            3 :   auto &else_bb = ctx.basic_blocks[else_end_bb];
     633            3 :   if (else_bb.is_goto_terminated () && else_bb.successors.empty ())
     634            2 :     add_jump (else_end_bb, final_start_bb);
     635            3 : }
     636              : 
     637              : void
     638            0 : ExprStmtBuilder::visit (HIR::MatchExpr &expr)
     639              : {
     640            0 :   rust_sorry_at (expr.get_locus (), "match expressions are not supported");
     641              :   //  // TODO
     642              :   //  expr.get_scrutinee_expr ()->accept_vis (*this);
     643              :   //  PlaceId scrutinee = translated;
     644              :   //
     645              :   //  BasicBlockId final_bb = new_bb ();
     646              :   //
     647              :   //  BasicBlockId next_case_bb = new_bb ();
     648              :   //  for (auto &match_case : expr.get_match_cases ())
     649              :   //    {
     650              :   //      BasicBlockId body_bb = new_bb ();
     651              :   //
     652              :   //      BasicBlockId next_pattern_bb = new_bb ();
     653              :   //      for (auto &pat : match_case.get_arm ().get_patterns ())
     654              :   //    {
     655              :   //      compile_pattern_validation (*pat, scrutinee);
     656              :   //      push_switch (translated);
     657              :   //      add_jump_to (next_pattern_bb);
     658              :   //      start_new_subsequent_bb ();
     659              :   //      compile_pattern_bindings (*pat, scrutinee);
     660              :   //      add_jump_to (body_bb);
     661              :   //
     662              :   //      ctx.current_bb = next_pattern_bb;
     663              :   //      next_pattern_bb = new_bb ();
     664              :   //    }
     665              :   //      ctx.current_bb = next_pattern_bb;
     666              :   //      // No pattern matched, go to the next case.
     667              :   //      add_jump_to (next_case_bb);
     668              :   //
     669              :   //      ctx.current_bb = body_bb;
     670              :   //      match_case.get_expr ()->accept_vis (*this);
     671              :   //      add_jump_to (final_bb);
     672              :   //
     673              :   //      ctx.current_bb = next_case_bb;
     674              :   //      next_case_bb = new_bb ();
     675              :   //    }
     676              :   //  add_jump_to (final_bb);
     677              :   //
     678              :   //  ctx.current_bb = final_bb;
     679            0 : }
     680              : 
     681              : void
     682            0 : ExprStmtBuilder::visit (HIR::AwaitExpr &expr)
     683              : {
     684            0 :   rust_sorry_at (expr.get_locus (), "await expressions are not supported");
     685            0 : }
     686              : 
     687              : void
     688            0 : ExprStmtBuilder::visit (HIR::AsyncBlockExpr &expr)
     689              : {
     690            0 :   rust_sorry_at (expr.get_locus (), "async blocks are not supported");
     691            0 : }
     692              : 
     693              : void
     694            0 : ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr)
     695              : {
     696              :   // Note: Type is only stored for the expr, not the segment.
     697            0 :   PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr));
     698            0 :   return_place (result, expr.get_locus ());
     699            0 : }
     700              : 
     701              : void
     702          108 : ExprStmtBuilder::visit (HIR::PathInExpression &expr)
     703              : {
     704              :   // Note: Type is only stored for the expr, not the segment.
     705          108 :   PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr));
     706          108 :   return_place (result, expr.get_locus ());
     707          108 : }
     708              : 
     709              : void
     710          103 : ExprStmtBuilder::visit (HIR::LetStmt &stmt)
     711              : {
     712          103 :   tl::optional<PlaceId> init;
     713          103 :   tl::optional<TyTy::BaseType *> type_annotation;
     714              : 
     715          103 :   if (stmt.has_type ())
     716            0 :     type_annotation = lookup_type (stmt.get_type ());
     717              : 
     718          103 :   if (stmt.get_pattern ().get_pattern_type () == HIR::Pattern::IDENTIFIER)
     719              :     {
     720              :       // Only if a pattern is just an identifier, no destructuring is needed.
     721              :       // Hoverer PatternBindingBuilder cannot change existing temporary
     722              :       // (init expr is evaluated before pattern binding) into a
     723              :       // variable, so it would emit extra assignment.
     724          103 :       auto var = declare_variable (stmt.get_pattern ().get_mappings ());
     725          103 :       if (stmt.has_type ())
     726            0 :         push_user_type_ascription (var, lookup_type (stmt.get_type ()));
     727              : 
     728          103 :       if (stmt.has_init_expr ())
     729          103 :         std::ignore = visit_expr (stmt.get_init_expr (), var);
     730              :     }
     731              :   else
     732              :     {
     733            0 :       if (stmt.has_init_expr ())
     734            0 :         init = visit_expr (stmt.get_init_expr ());
     735              : 
     736            0 :       PatternBindingBuilder (ctx, init, type_annotation)
     737            0 :         .go (stmt.get_pattern ());
     738              :     }
     739          103 : }
     740              : 
     741              : void
     742           11 : ExprStmtBuilder::visit (HIR::ExprStmt &stmt)
     743              : {
     744           11 :   PlaceId result = visit_expr (stmt.get_expr ());
     745              :   // We must read the value for current liveness and we must not store it into
     746              :   // the same place.
     747           11 :   if (result != INVALID_PLACE)
     748            4 :     push_tmp_assignment (result, stmt.get_locus ());
     749           11 : }
     750              : } // namespace BIR
     751              : } // 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.