LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors/borrowck - rust-bir-builder-internal.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.0 % 250 225
Test Date: 2026-10-03 16:17:38 Functions: 65.3 % 75 49
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              : #ifndef RUST_BIR_BUILDER_INTERNAL_H
      20              : #define RUST_BIR_BUILDER_INTERNAL_H
      21              : 
      22              : #include "rust-bir-place.h"
      23              : #include "rust-hir-expr.h"
      24              : #include "rust-hir-item.h"
      25              : #include "rust-hir-type-check.h"
      26              : #include "rust-hir-visitor.h"
      27              : #include "rust-bir.h"
      28              : #include "rust-bir-free-region.h"
      29              : #include "rust-finalized-name-resolution-context.h"
      30              : #include "options.h"
      31              : #include "rust-rib.h"
      32              : 
      33              : namespace Rust {
      34              : 
      35              : namespace TyTy {
      36              : 
      37              : using Variance = VarianceAnalysis::Variance;
      38              : 
      39              : class RenumberCtx
      40              : {
      41              :   Polonius::Origin next_region = 0;
      42              : 
      43              : public:
      44              :   Polonius::Origin get_next_region () { return next_region++; }
      45              : };
      46              : 
      47              : } // namespace TyTy
      48              : 
      49              : namespace BIR {
      50              : 
      51              : /** Holds the context of BIR building so that it can be shared/passed between
      52              :  * different builders. */
      53              : struct BuilderContext
      54              : {
      55              :   struct LoopAndLabelCtx
      56              :   {
      57              :     bool is_loop;      // Loop or labelled block
      58              :     NodeId label;      // UNKNOWN_NODEID if no label (loop)
      59              :     PlaceId label_var; // For break with value.
      60              :     BasicBlockId break_bb;
      61              :     BasicBlockId continue_bb; // Only valid for loops
      62              :     ScopeId continue_scope;
      63              :     // Break scope is the parent of the `continue_scope`.
      64              : 
      65            0 :     LoopAndLabelCtx (bool is_loop = false, NodeId label = UNKNOWN_NODEID,
      66              :                      PlaceId label_var = INVALID_PLACE,
      67              :                      BasicBlockId break_bb = INVALID_BB,
      68              :                      BasicBlockId continue_bb = INVALID_BB,
      69              :                      ScopeId continue_scope = INVALID_SCOPE)
      70            0 :       : is_loop (is_loop), label (label), label_var (label_var),
      71            0 :         break_bb (break_bb), continue_bb (continue_bb),
      72            0 :         continue_scope (continue_scope)
      73              :     {}
      74              :   };
      75              : 
      76              :   // External context.
      77              :   Resolver::TypeCheckContext &tyctx;
      78              :   const Resolver2_0::FinalizedNameResolutionContext &resolver;
      79              : 
      80              :   // BIR output
      81              :   BasicBlocks basic_blocks;
      82              :   BasicBlockId current_bb = ENTRY_BASIC_BLOCK;
      83              : 
      84              :   /**
      85              :    * Allocation and lookup of places (variables, temporaries, paths, and
      86              :    * constants)
      87              :    */
      88              :   PlaceDB place_db;
      89              :   RegionBinder region_binder{place_db.expose_next_free_region ()};
      90              : 
      91              :   // Used for cleaner dump.
      92              :   std::vector<PlaceId> arguments;
      93              :   /**
      94              :    * Since labels can be used to return values, we need to reserve a place for
      95              :    * them. This map associates labels with their respective places.
      96              :    */
      97              :   std::unordered_map<NodeId, PlaceId> label_place_map;
      98              : 
      99              :   /** Context for current situation (loop, label, etc.) */
     100              :   std::vector<LoopAndLabelCtx> loop_and_label_stack;
     101              : 
     102              :   FreeRegions fn_free_regions{{}};
     103              : 
     104              : public:
     105           57 :   BuilderContext ()
     106           57 :     : tyctx (*Resolver::TypeCheckContext::get ()),
     107           57 :       resolver (Resolver2_0::FinalizedNameResolutionContext::get ())
     108              :   {
     109           57 :     basic_blocks.emplace_back (); // StartBB
     110           57 :   }
     111              : 
     112          249 :   BasicBlock &get_current_bb () { return basic_blocks[current_bb]; }
     113              : 
     114              :   const LoopAndLabelCtx &lookup_label (NodeId label)
     115              :   {
     116              :     auto label_match = [label] (const LoopAndLabelCtx &info) {
     117              :       return info.label != UNKNOWN_NODEID && info.label == label;
     118              :     };
     119              : 
     120              :     auto found = std::find_if (loop_and_label_stack.rbegin (),
     121              :                                loop_and_label_stack.rend (), label_match);
     122              :     rust_assert (found != loop_and_label_stack.rend ());
     123              :     return *found;
     124              :   }
     125              : };
     126              : 
     127              : /** Common infrastructure for building BIR from HIR. */
     128              : class AbstractBuilder
     129              : {
     130              : protected:
     131              :   BuilderContext &ctx;
     132              : 
     133              :   /**
     134              :    * This emulates the return value of the visitor, to be able to use the
     135              :    * current visitor infrastructure, where the return value is forced to be
     136              :    * void.
     137              :    */
     138              :   PlaceId translated = INVALID_PLACE;
     139              : 
     140              : protected:
     141           84 :   explicit AbstractBuilder (BuilderContext &ctx) : ctx (ctx) {}
     142              : 
     143          137 :   PlaceId declare_variable (const Analysis::NodeMapping &node,
     144              :                             bool user_type_annotation = false)
     145              :   {
     146          137 :     return declare_variable (node, lookup_type (node.get_hirid ()),
     147          137 :                              user_type_annotation);
     148              :   }
     149              : 
     150          137 :   PlaceId declare_variable (const Analysis::NodeMapping &node,
     151              :                             TyTy::BaseType *ty,
     152              :                             bool user_type_annotation = false)
     153              :   {
     154          137 :     const NodeId nodeid = node.get_nodeid ();
     155              : 
     156              :     // In debug mode, check that the variable is not already declared.
     157          137 :     rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
     158              : 
     159          137 :     auto place_id = ctx.place_db.add_variable (nodeid, ty);
     160              : 
     161          137 :     if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE)
     162          137 :       push_storage_live (place_id);
     163              : 
     164          137 :     if (user_type_annotation)
     165            0 :       push_user_type_ascription (place_id, ty);
     166              : 
     167          137 :     return place_id;
     168              :   }
     169              : 
     170           28 :   PlaceId declare_argument (const Analysis::NodeMapping &node,
     171              :                             TyTy::BaseType *ty)
     172              :   {
     173           28 :     const NodeId nodeid = node.get_nodeid ();
     174              : 
     175              :     // In debug mode, check that the argument is not already declared.
     176           28 :     rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
     177              : 
     178           28 :     return ctx.place_db.add_variable (nodeid, ty);
     179              :   }
     180              : 
     181           76 :   void push_new_scope () { ctx.place_db.push_new_scope (); }
     182              : 
     183          250 :   void push_drop (PlaceId place)
     184              :   {
     185          250 :     ctx.get_current_bb ().statements.push_back (Statement::make_drop (place));
     186          250 :   }
     187              : 
     188           59 :   void push_function_argument_drops ()
     189              :   {
     190           59 :     std::for_each (ctx.arguments.rbegin (), ctx.arguments.rend (),
     191           32 :                    [&] (PlaceId argument) { push_drop (argument); });
     192           59 :   }
     193              : 
     194           74 :   void pop_scope ()
     195              :   {
     196           74 :     auto &scope = ctx.place_db.get_current_scope ();
     197           74 :     if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE)
     198              :       {
     199           74 :         std::for_each (scope.locals.rbegin (), scope.locals.rend (),
     200          212 :                        [&] (PlaceId place) {
     201          212 :                          push_drop (place);
     202          212 :                          push_storage_dead (place);
     203          212 :                        });
     204              :       }
     205           74 :     ctx.place_db.pop_scope ();
     206           74 :   }
     207              : 
     208              :   bool intersection_empty (std::vector<PlaceId> &a, std::vector<PlaceId> &b)
     209              :   {
     210              :     for (auto &place : a)
     211              :       {
     212              :         if (std::find (b.begin (), b.end (), place) != b.end ())
     213              :           return false;
     214              :       }
     215              :     return true;
     216              :   }
     217              : 
     218            2 :   void unwind_until (ScopeId final_scope)
     219              :   {
     220            2 :     auto current_scope_id = ctx.place_db.get_current_scope_id ();
     221            6 :     while (current_scope_id != final_scope)
     222              :       {
     223            4 :         auto &scope = ctx.place_db.get_scope (current_scope_id);
     224              : 
     225              :         // TODO: Perform stable toposort based on `borrowed_by`.
     226              : 
     227            4 :         std::for_each (scope.locals.rbegin (), scope.locals.rend (),
     228            6 :                        [&] (PlaceId place) {
     229            6 :                          push_drop (place);
     230            6 :                          push_storage_dead (place);
     231            6 :                        });
     232            4 :         current_scope_id = scope.parent;
     233              :       }
     234            2 :   }
     235              : 
     236           85 :   FreeRegions bind_regions (std::vector<TyTy::Region> regions,
     237              :                             FreeRegions parent_free_regions)
     238              :   {
     239           85 :     FreeRegions free_regions;
     240          106 :     for (auto &region : regions)
     241              :       {
     242           21 :         if (region.is_early_bound ())
     243              :           {
     244           18 :             free_regions.push_back (parent_free_regions[region.get_index ()]);
     245              :           }
     246            3 :         else if (region.is_static ())
     247              :           {
     248            1 :             free_regions.push_back (STATIC_FREE_REGION);
     249              :           }
     250            2 :         else if (region.is_anonymous ())
     251              :           {
     252            2 :             free_regions.push_back (ctx.place_db.get_next_free_region ());
     253              :           }
     254            0 :         else if (region.is_named ())
     255              :           {
     256            0 :             rust_unreachable (); // FIXME
     257              :           }
     258              :         else
     259              :           {
     260            0 :             rust_sorry_at (UNKNOWN_LOCATION, "Unimplemented");
     261            0 :             rust_unreachable ();
     262              :           }
     263              :       }
     264           85 :     return free_regions;
     265              :   }
     266              : 
     267              : protected: // Helpers to add BIR statements
     268          279 :   void push_assignment (PlaceId lhs, AbstractExpr *rhs, location_t location,
     269              :                         tl::optional<HirId> move_site = tl::nullopt)
     270              :   {
     271          279 :     ctx.get_current_bb ().statements.push_back (
     272          279 :       Statement::make_assignment (lhs, rhs, location, move_site));
     273          279 :     translated = lhs;
     274          279 :   }
     275              : 
     276          133 :   void push_assignment (PlaceId lhs, PlaceId rhs, location_t location,
     277              :                         tl::optional<HirId> move_site = tl::nullopt)
     278              :   {
     279          133 :     push_assignment (lhs, new Assignment (rhs), location, move_site);
     280          133 :   }
     281              : 
     282           77 :   void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty,
     283              :                             location_t location,
     284              :                             tl::optional<HirId> move_site = tl::nullopt)
     285              :   {
     286           77 :     PlaceId tmp = ctx.place_db.add_temporary (tyty);
     287           77 :     push_storage_live (tmp);
     288           77 :     push_assignment (tmp, rhs, location, move_site);
     289           77 :   }
     290              : 
     291           40 :   void push_tmp_assignment (PlaceId rhs, location_t location,
     292              :                             tl::optional<HirId> move_site = tl::nullopt)
     293              :   {
     294           40 :     push_tmp_assignment (new Assignment (rhs), ctx.place_db[rhs].tyty, location,
     295              :                          move_site);
     296           40 :   }
     297              : 
     298           14 :   void push_switch (PlaceId switch_val, location_t location,
     299              :                     std::initializer_list<BasicBlockId> destinations = {})
     300              :   {
     301           14 :     auto copy = move_place (switch_val, location);
     302           14 :     ctx.get_current_bb ().statements.push_back (Statement::make_switch (copy));
     303           14 :     ctx.get_current_bb ().successors.insert (
     304           14 :       ctx.get_current_bb ().successors.end (), destinations);
     305           14 :   }
     306              : 
     307           17 :   void push_goto (BasicBlockId bb)
     308              :   {
     309           17 :     ctx.get_current_bb ().statements.push_back (Statement::make_goto ());
     310           17 :     if (bb != INVALID_BB) // INVALID_BB means the goto will be resolved later.
     311            0 :       ctx.get_current_bb ().successors.push_back (bb);
     312           17 :   }
     313              : 
     314          214 :   void push_storage_live (PlaceId place)
     315              :   {
     316          214 :     ctx.get_current_bb ().statements.push_back (
     317          214 :       Statement::make_storage_live (place));
     318          214 :   }
     319              : 
     320          218 :   void push_storage_dead (PlaceId place)
     321              :   {
     322          218 :     ctx.get_current_bb ().statements.push_back (
     323          218 :       Statement::make_storage_dead (place));
     324          218 :   }
     325              : 
     326            0 :   void push_user_type_ascription (PlaceId place, TyTy::BaseType *ty)
     327              :   {
     328            0 :     ctx.get_current_bb ().statements.push_back (
     329            0 :       Statement::make_user_type_ascription (place, ty));
     330            0 :   }
     331              : 
     332          138 :   void push_fake_read (PlaceId place)
     333              :   {
     334          138 :     ctx.get_current_bb ().statements.push_back (
     335          138 :       Statement::make_fake_read (place));
     336          138 :   }
     337              : 
     338           59 :   void push_return (location_t location)
     339              :   {
     340           59 :     push_function_argument_drops ();
     341              : 
     342           59 :     ctx.get_current_bb ().statements.push_back (
     343           59 :       Statement::make_return (location));
     344           59 :   }
     345              : 
     346           13 :   PlaceId borrow_place (PlaceId place_id, TyTy::BaseType *ty,
     347              :                         location_t location)
     348              :   {
     349           13 :     auto mutability = ty->as<const TyTy::ReferenceType> ()->mutability ();
     350           13 :     auto loan = ctx.place_db.add_loan ({mutability, place_id, location});
     351           13 :     push_tmp_assignment (
     352              :       new BorrowExpr (place_id, loan,
     353           13 :                       ctx.place_db.get_next_free_region ().value),
     354              :       ty, location);
     355           13 :     return translated;
     356              :   }
     357              : 
     358           70 :   PlaceId move_place (PlaceId arg, location_t location,
     359              :                       tl::optional<HirId> move_site = tl::nullopt)
     360              :   {
     361           70 :     auto &place = ctx.place_db[arg];
     362              : 
     363           70 :     if (place.is_constant ())
     364           30 :       return arg;
     365              : 
     366           40 :     if (place.tyty->is<TyTy::ReferenceType> ())
     367           13 :       return reborrow_place (arg, location);
     368              : 
     369           27 :     if (place.is_rvalue ())
     370            6 :       return arg;
     371              : 
     372           21 :     push_tmp_assignment (arg, location, move_site);
     373           21 :     return translated;
     374              :   }
     375              : 
     376           13 :   PlaceId reborrow_place (PlaceId arg, location_t location)
     377              :   {
     378           13 :     auto ty = ctx.place_db[arg].tyty->as<TyTy::ReferenceType> ();
     379           13 :     return borrow_place (ctx.place_db.lookup_or_add_path (Place::DEREF,
     380              :                                                           ty->get_base (), arg),
     381           13 :                          ty, location);
     382              :   }
     383              : 
     384              :   template <typename T>
     385           51 :   void move_all (T &args, std::vector<location_t> locations,
     386              :                  tl::optional<HirId> move_site = tl::nullopt)
     387              :   {
     388           51 :     rust_assert (args.size () == locations.size ());
     389           51 :     std::transform (args.begin (), args.end (), locations.begin (),
     390              :                     args.begin (),
     391           49 :                     [this, move_site] (PlaceId arg, location_t location) {
     392           49 :                       return move_place (arg, location, move_site);
     393              :                     });
     394           51 :   }
     395              : 
     396              : protected: // CFG helpers
     397           57 :   BasicBlockId new_bb ()
     398              :   {
     399           57 :     ctx.basic_blocks.emplace_back ();
     400           57 :     return {ctx.basic_blocks.size () - 1};
     401              :   }
     402              : 
     403           24 :   BasicBlockId start_new_consecutive_bb ()
     404              :   {
     405           24 :     BasicBlockId bb = new_bb ();
     406           24 :     if (!ctx.get_current_bb ().is_terminated ())
     407              :       {
     408            0 :         push_goto (bb);
     409              :       }
     410              :     else
     411              :       {
     412           24 :         add_jump_to (bb);
     413              :       }
     414           24 :     ctx.current_bb = bb;
     415           24 :     return bb;
     416              :   }
     417              : 
     418           69 :   void add_jump (BasicBlockId from, BasicBlockId to)
     419              :   {
     420           31 :     ctx.basic_blocks[from].successors.emplace_back (to);
     421              :   }
     422              : 
     423           24 :   void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); }
     424              : 
     425              : protected: // HIR resolution helpers
     426              :   template <typename T>
     427          458 :   WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (T &hir_node) const
     428              :   {
     429          458 :     return lookup_type (hir_node.get_mappings ().get_hirid ());
     430              :   }
     431              : 
     432          595 :   WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (HirId hirid) const
     433              :   {
     434          595 :     TyTy::BaseType *type = nullptr;
     435          595 :     bool ok = ctx.tyctx.lookup_type (hirid, &type);
     436          595 :     rust_assert (ok);
     437          595 :     rust_assert (type != nullptr);
     438          595 :     return type;
     439              :   }
     440              : 
     441            0 :   template <typename T> NodeId resolve_label (T &expr)
     442              :   {
     443            0 :     auto res = ctx.resolver.lookup (expr.get_mappings ().get_nodeid (),
     444              :                                     Resolver2_0::Namespace::Labels);
     445            0 :     rust_assert (res.has_value ());
     446            0 :     return res.value ();
     447              :   }
     448              : 
     449            6 :   template <typename T> PlaceId resolve_variable (T &variable)
     450              :   {
     451            6 :     auto res = ctx.resolver.lookup (variable.get_mappings ().get_nodeid (),
     452              :                                     Resolver2_0::Namespace::Values);
     453            6 :     rust_assert (res.has_value ());
     454            6 :     return ctx.place_db.lookup_variable (res.value ());
     455              :   }
     456              : 
     457              :   template <typename T>
     458          140 :   PlaceId resolve_variable_or_fn (T &variable, TyTy::BaseType *ty)
     459              :   {
     460          140 :     ty = (ty) ? ty : lookup_type (variable);
     461              : 
     462              :     // Unlike variables,
     463              :     // functions do not have to be declared in PlaceDB before use.
     464          140 :     if (ty->is<TyTy::FnType> ())
     465           24 :       return ctx.place_db.get_constant (ty);
     466              : 
     467          116 :     auto res = ctx.resolver.lookup (variable.get_mappings ().get_nodeid (),
     468              :                                     Resolver2_0::Namespace::Values);
     469          116 :     rust_assert (res.has_value ());
     470          116 :     return ctx.place_db.lookup_or_add_variable (res.value (), ty);
     471              :   }
     472              : 
     473              : protected: // Implicit conversions.
     474              :   /**
     475              :    * Performs implicit coercions on the `translated` place defined for a
     476              :    * coercion site.
     477              :    *
     478              :    * Reference: https://doc.rust-lang.org/reference/type-coercions.html
     479              :    *
     480              :    * The only coercion relevant to BIR is the autoderef. All other coercions
     481              :    * will be taken in account because the type is extracted from each node and
     482              :    * not derived from operations in HIR/BIR. The borrowck does not care about
     483              :    * type transitions. Lifetimes are not coerced, rather new are created with
     484              :    * defined bounds to the original ones.
     485              :    */
     486           49 :   void coercion_site (PlaceId &place, TyTy::BaseType *expected_ty)
     487              :   {
     488          147 :     auto count_ref_levels = [] (TyTy::BaseType *ty) {
     489           98 :       size_t count = 0;
     490          122 :       while (auto r = ty->try_as<TyTy::ReferenceType> ())
     491              :         {
     492           24 :           ty = r->get_base ();
     493           24 :           count++;
     494           24 :         }
     495           98 :       return count;
     496              :     };
     497              : 
     498           49 :     auto actual_ty = ctx.place_db[place].tyty;
     499              : 
     500           49 :     auto deref_count
     501           49 :       = count_ref_levels (actual_ty) - count_ref_levels (expected_ty);
     502              : 
     503           49 :     for (size_t i = 0; i < deref_count; ++i)
     504              :       {
     505            0 :         actual_ty = actual_ty->as<TyTy::ReferenceType> ()->get_base ();
     506            0 :         place
     507            0 :           = ctx.place_db.lookup_or_add_path (Place::DEREF, actual_ty, place);
     508              :       }
     509           49 :   }
     510              : 
     511              :   /** Dereferences the `translated` place until it is at most one reference
     512              :    * and return the base type. */
     513            5 :   TyTy::BaseType *autoderef (PlaceId &place)
     514              :   {
     515            5 :     auto ty = ctx.place_db[place].tyty;
     516            6 :     while (auto ref_ty = ty->try_as<TyTy::ReferenceType> ())
     517              :       {
     518            1 :         ty = ref_ty->get_base ();
     519            1 :         place = ctx.place_db.lookup_or_add_path (Place::DEREF, ty, place);
     520            1 :       }
     521            5 :     return ty;
     522              :   }
     523              : 
     524              :   void autoref ()
     525              :   {
     526              :     if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF)
     527              :       {
     528              :         // FIXME: not sure how to fetch correct location for this
     529              :         // this function is unused yet, so can ignore for now
     530              :         auto ty = ctx.place_db[translated].tyty;
     531              :         translated
     532              :           = borrow_place (translated,
     533              :                           new TyTy::ReferenceType (ty->get_ref (),
     534              :                                                    TyTy::TyVar (ty->get_ref ()),
     535              :                                                    Mutability::Imm),
     536              :                           UNKNOWN_LOCATION);
     537              :       }
     538              :   }
     539              : };
     540              : 
     541              : class AbstractExprBuilder : public AbstractBuilder,
     542              :                             public HIR::HIRExpressionVisitor
     543              : {
     544              : protected:
     545              :   /**
     546              :    * Optional place for the result of the evaluated expression.
     547              :    * Valid if value is not `INVALID_PLACE`.
     548              :    * Used when return place must be created by caller (return for if-else).
     549              :    */
     550              :   PlaceId expr_return_place = INVALID_PLACE;
     551              : 
     552              : protected:
     553           80 :   explicit AbstractExprBuilder (BuilderContext &ctx,
     554              :                                 PlaceId expr_return_place = INVALID_PLACE)
     555           80 :     : AbstractBuilder (ctx), expr_return_place (expr_return_place)
     556              :   {}
     557              : 
     558              :   /**
     559              :    * Wrapper that provides return value based API inside a visitor which has
     560              :    * to use global state to pass the data around.
     561              :    * @param dst_place Place to assign the produced value to, optionally
     562              :    * allocated by the caller.
     563              :    * */
     564          411 :   PlaceId visit_expr (HIR::Expr &expr, PlaceId dst_place = INVALID_PLACE)
     565              :   {
     566              :     // Save to support proper recursion.
     567          411 :     auto saved = expr_return_place;
     568          411 :     expr_return_place = dst_place;
     569          411 :     translated = INVALID_PLACE;
     570          406 :     expr.accept_vis (*this);
     571          411 :     expr_return_place = saved;
     572          411 :     auto result = translated;
     573          411 :     translated = INVALID_PLACE;
     574          406 :     return result;
     575              :   }
     576              : 
     577              :   /**
     578              :    * Create a return value of a subexpression, which produces an expression.
     579              :    * Use `return_place` for subexpression that only produce a place (look it
     580              :    * up) to avoid needless assignments.
     581              :    *
     582              :    * @param can_panic mark that expression can panic to insert jump to
     583              :    * cleanup.
     584              :    */
     585           93 :   void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, location_t location,
     586              :                     bool can_panic = false)
     587              :   {
     588           93 :     if (expr_return_place != INVALID_PLACE)
     589              :       {
     590           69 :         push_assignment (expr_return_place, expr, location);
     591              :       }
     592              :     else
     593              :       {
     594           24 :         push_tmp_assignment (expr, ty, location);
     595              :       }
     596              : 
     597           93 :     if (can_panic)
     598              :       {
     599           24 :         start_new_consecutive_bb ();
     600              :       }
     601              : 
     602           93 :     if (ty->is<TyTy::ReferenceType> ()
     603           93 :         || ctx.place_db[translated].is_constant ())
     604              :       {
     605           43 :         push_fake_read (translated);
     606              :       }
     607           93 :   }
     608              : 
     609              :   /** Mark place to be a result of processed subexpression. */
     610          249 :   void return_place (PlaceId place, location_t location, bool can_panic = false,
     611              :                      tl::optional<HirId> move_site = tl::nullopt)
     612              :   {
     613          249 :     if (expr_return_place != INVALID_PLACE)
     614              :       {
     615              :         // Return place is already allocated, no need to defer assignment.
     616           81 :         push_assignment (expr_return_place, place, location, move_site);
     617              :       }
     618              :     else
     619              :       {
     620          168 :         translated = place;
     621              :       }
     622              : 
     623          249 :     if (can_panic)
     624              :       {
     625            0 :         start_new_consecutive_bb ();
     626              :       }
     627              : 
     628          249 :     if (ctx.place_db[place].is_constant ())
     629              :       {
     630           95 :         push_fake_read (translated);
     631              :       }
     632          249 :   }
     633              : 
     634              :   /** Explicitly return a unit value. Expression produces no value. */
     635            9 :   void return_unit (HIR::Expr &expr)
     636              :   {
     637            9 :     translated = ctx.place_db.get_constant (lookup_type (expr));
     638            9 :   }
     639              : 
     640           42 :   PlaceId return_borrowed (PlaceId place_id, TyTy::BaseType *ty,
     641              :                            location_t location)
     642              :   {
     643              :     // TODO: deduplicate with borrow_place
     644           42 :     auto loan = ctx.place_db.add_loan (
     645           42 :       {ty->as<const TyTy::ReferenceType> ()->mutability (), place_id,
     646              :        location});
     647           42 :     return_expr (new BorrowExpr (place_id, loan,
     648           42 :                                  ctx.place_db.get_next_free_region ().value),
     649              :                  ty, location);
     650           42 :     return translated;
     651              :   }
     652              : 
     653           28 :   PlaceId take_or_create_return_place (TyTy::BaseType *type)
     654              :   {
     655           28 :     PlaceId result = INVALID_PLACE;
     656           28 :     if (expr_return_place != INVALID_PLACE)
     657              :       {
     658           28 :         result = expr_return_place;
     659           28 :         expr_return_place = INVALID_PLACE;
     660              :       }
     661              :     else
     662              :       {
     663            0 :         result = ctx.place_db.add_temporary (type);
     664            0 :         push_storage_live (result);
     665              :       }
     666           28 :     return result;
     667              :   }
     668              : };
     669              : 
     670              : /**
     671              :  * Helper to convert a pointer to an optional. Maps nullptr to nullopt.
     672              :  * Optionals are mainly used here to provide monadic operations (map) over
     673              :  * possibly null pointers.
     674              :  */
     675              : template <typename T>
     676              : tl::optional<T>
     677              : optional_from_ptr (T ptr)
     678              : {
     679              :   if (ptr != nullptr)
     680              :     return {ptr};
     681              :   else
     682              :     return tl::nullopt;
     683              : }
     684              : 
     685              : } // namespace BIR
     686              : } // namespace Rust
     687              : 
     688              : #endif // RUST_BIR_BUILDER_INTERNAL_H
        

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.