LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors/borrowck - rust-bir-fact-collector.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 0.0 % 476 0
Test Date: 2024-12-21 13:15:12 Functions: 0.0 % 49 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2024 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_FACT_COLLECTOR_H
      20                 :             : #define RUST_BIR_FACT_COLLECTOR_H
      21                 :             : 
      22                 :             : #include "rust-bir-visitor.h"
      23                 :             : #include "rust-bir.h"
      24                 :             : #include "rust-bir-place.h"
      25                 :             : #include "polonius/rust-polonius.h"
      26                 :             : 
      27                 :             : namespace Rust {
      28                 :             : namespace BIR {
      29                 :             : 
      30                 :             : enum class PointPosition : uint8_t
      31                 :             : {
      32                 :             :   START,
      33                 :             :   MID
      34                 :             : };
      35                 :             : 
      36                 :             : class FactCollector : public Visitor
      37                 :             : {
      38                 :             :   // Output.
      39                 :             :   Polonius::Facts facts;
      40                 :             : 
      41                 :             :   // Read-only context.
      42                 :             :   const PlaceDB &place_db;
      43                 :             :   const std::vector<BasicBlock> &basic_blocks;
      44                 :             :   const PlaceId first_local;
      45                 :             :   const location_t location;
      46                 :             : 
      47                 :             :   Resolver::TypeCheckContext &tyctx;
      48                 :             : 
      49                 :             :   // Collector state.
      50                 :             :   BasicBlockId current_bb = 0;
      51                 :             :   uint32_t current_stmt = 0;
      52                 :             :   PlaceId lhs = INVALID_PLACE;
      53                 :             : 
      54                 :             :   // PlaceDB is const in this phase, so this is used to generate fresh regions.
      55                 :             :   FreeRegion next_fresh_region;
      56                 :             :   RegionBinder region_binder{next_fresh_region};
      57                 :             : 
      58                 :             :   std::vector<Polonius::Point> cfg_points_all;
      59                 :             : 
      60                 :           0 :   FreeRegions bind_regions (std::vector<TyTy::Region> regions,
      61                 :             :                             FreeRegions parent_free_regions)
      62                 :             :   {
      63                 :           0 :     return region_binder.bind_regions (regions, parent_free_regions);
      64                 :             :   }
      65                 :             : 
      66                 :           0 :   FreeRegions make_fresh_regions (size_t size)
      67                 :             :   {
      68                 :           0 :     std::vector<FreeRegion> free_regions;
      69                 :           0 :     for (size_t i = 0; i < size; i++)
      70                 :           0 :       free_regions.push_back (region_binder.get_next_free_region ());
      71                 :             : 
      72                 :           0 :     return FreeRegions (std::move (free_regions));
      73                 :           0 :   }
      74                 :             : 
      75                 :             : public:
      76                 :           0 :   static Polonius::Facts collect (Function &func)
      77                 :             :   {
      78                 :           0 :     FactCollector collector (func);
      79                 :           0 :     collector.init_universal_regions (func.universal_regions,
      80                 :           0 :                                       func.universal_region_bounds);
      81                 :             : 
      82                 :           0 :     collector.visit_statemensts ();
      83                 :           0 :     collector.visit_places (func.arguments);
      84                 :             : 
      85                 :           0 :     return std::move (collector.facts);
      86                 :           0 :   }
      87                 :             : 
      88                 :             : protected: // Constructor and destructor.
      89                 :           0 :   explicit FactCollector (Function &func)
      90                 :           0 :     : place_db (func.place_db), basic_blocks (func.basic_blocks),
      91                 :           0 :       first_local (func.arguments.empty () ? FIRST_VARIABLE_PLACE
      92                 :           0 :                                            : *func.arguments.rbegin () + 1),
      93                 :           0 :       location (func.location), tyctx (*Resolver::TypeCheckContext::get ()),
      94                 :           0 :       next_fresh_region (place_db.peek_next_free_region ())
      95                 :           0 :   {}
      96                 :           0 :   ~FactCollector () = default;
      97                 :             : 
      98                 :             : protected: // Main collection entry points (for different categories).
      99                 :           0 :   void init_universal_regions (
     100                 :             :     const FreeRegions &universal_regions,
     101                 :             :     const decltype (Function::universal_region_bounds) &universal_region_bounds)
     102                 :             :   {
     103                 :           0 :     size_t next_loan = place_db.get_loans ().size ();
     104                 :           0 :     facts.universal_region.emplace_back (0);
     105                 :           0 :     facts.placeholder.emplace_back (0, next_loan++);
     106                 :             : 
     107                 :           0 :     for (auto &region : universal_regions)
     108                 :             :       {
     109                 :           0 :         facts.universal_region.emplace_back (region);
     110                 :           0 :         facts.placeholder.emplace_back (region, next_loan++);
     111                 :           0 :         facts.known_placeholder_subset.emplace_back (0, region);
     112                 :             :       }
     113                 :             : 
     114                 :             :     // Copy already collected subset facts, that are universally valid.
     115                 :           0 :     for (auto &bound : universal_region_bounds)
     116                 :           0 :       facts.known_placeholder_subset.emplace_back (bound.first, bound.second);
     117                 :           0 :   }
     118                 :             : 
     119                 :           0 :   void visit_places (const std::vector<PlaceId> &args)
     120                 :             :   {
     121                 :           0 :     for (PlaceId place_id = 0; place_id < place_db.size (); ++place_id)
     122                 :             :       {
     123                 :           0 :         auto &place = place_db[place_id];
     124                 :             : 
     125                 :           0 :         switch (place.kind)
     126                 :             :           {
     127                 :           0 :           case Place::VARIABLE:
     128                 :           0 :           case Place::TEMPORARY:
     129                 :           0 :             facts.path_is_var.emplace_back (place_id, place_id);
     130                 :           0 :             for (auto &region : place.regions)
     131                 :           0 :               facts.use_of_var_derefs_origin.emplace_back (place_id, region);
     132                 :             : 
     133                 :             :             // TODO: drop_of_var_derefs_origin
     134                 :             :             break;
     135                 :           0 :           case Place::FIELD:
     136                 :           0 :             sanizite_field (place_id);
     137                 :           0 :             facts.child_path.emplace_back (place_id, place.path.parent);
     138                 :           0 :             break;
     139                 :           0 :           case Place::INDEX:
     140                 :           0 :             push_subset_all (place.tyty, place.regions,
     141                 :           0 :                              place_db[place.path.parent].regions);
     142                 :           0 :             facts.child_path.emplace_back (place_id, place.path.parent);
     143                 :           0 :             break;
     144                 :           0 :           case Place::DEREF:
     145                 :           0 :             sanitize_deref (place_id);
     146                 :           0 :             facts.child_path.emplace_back (place_id, place.path.parent);
     147                 :           0 :             break;
     148                 :             :           case Place::CONSTANT:
     149                 :             :           case Place::INVALID:
     150                 :             :             break;
     151                 :             :           }
     152                 :             :       }
     153                 :             : 
     154                 :           0 :     for (PlaceId arg = FIRST_VARIABLE_PLACE + 1; arg < first_local; ++arg)
     155                 :           0 :       facts.path_assigned_at_base.emplace_back (
     156                 :           0 :         arg, get_point (0, 0, PointPosition::START));
     157                 :             : 
     158                 :           0 :     for (PlaceId place = first_local; place < place_db.size (); ++place)
     159                 :             :       {
     160                 :           0 :         if (place_db[place].is_var ())
     161                 :           0 :           facts.path_moved_at_base.emplace_back (
     162                 :           0 :             place, get_point (0, 0, PointPosition::START));
     163                 :             :       }
     164                 :           0 :   }
     165                 :             : 
     166                 :           0 :   void sanitize_deref (PlaceId place_id)
     167                 :             :   {
     168                 :           0 :     auto &place = place_db[place_id];
     169                 :           0 :     auto &base = place_db[place.path.parent];
     170                 :             : 
     171                 :           0 :     rust_debug ("\tSanitize deref of %s", base.tyty->as_string ().c_str ());
     172                 :             : 
     173                 :           0 :     std::vector<Polonius::Origin> regions;
     174                 :           0 :     regions.insert (regions.end (), base.regions.begin () + 1,
     175                 :             :                     base.regions.end ());
     176                 :           0 :     FreeRegions r (std::move (regions));
     177                 :           0 :     push_subset_all (place.tyty, r, place.regions);
     178                 :           0 :   }
     179                 :           0 :   void sanizite_field (PlaceId place_id)
     180                 :             :   {
     181                 :           0 :     auto &place = place_db[place_id];
     182                 :           0 :     auto &base = place_db[place.path.parent];
     183                 :             : 
     184                 :           0 :     rust_debug ("\tSanitize field .%d of %s", place.variable_or_field_index,
     185                 :             :                 base.tyty->as_string ().c_str ());
     186                 :             : 
     187                 :           0 :     if (base.tyty->is<TyTy::TupleType> ())
     188                 :           0 :       return;
     189                 :           0 :     auto r = Resolver::TypeCheckContext::get ()
     190                 :           0 :                ->get_variance_analysis_ctx ()
     191                 :           0 :                .query_field_regions (base.tyty->as<TyTy::ADTType> (), 0,
     192                 :           0 :                                      place.variable_or_field_index,
     193                 :           0 :                                      base.regions); // FIXME
     194                 :           0 :     FreeRegions f (std::move (r));
     195                 :           0 :     push_subset_all (place.tyty, f, place.regions);
     196                 :           0 :   }
     197                 :             : 
     198                 :           0 :   void visit_statemensts ()
     199                 :             :   {
     200                 :           0 :     rust_debug ("visit_statemensts");
     201                 :             : 
     202                 :           0 :     for (current_bb = 0; current_bb < basic_blocks.size (); ++current_bb)
     203                 :             :       {
     204                 :           0 :         auto &bb = basic_blocks[current_bb];
     205                 :           0 :         for (current_stmt = 0; current_stmt < bb.statements.size ();
     206                 :           0 :              ++current_stmt)
     207                 :             :           {
     208                 :           0 :             cfg_points_all.push_back (get_current_point_start ());
     209                 :           0 :             cfg_points_all.push_back (get_current_point_mid ());
     210                 :             : 
     211                 :           0 :             add_stmt_to_cfg (current_bb, current_stmt);
     212                 :             : 
     213                 :           0 :             visit (bb.statements[current_stmt]);
     214                 :             :           }
     215                 :             :       }
     216                 :           0 :     current_bb = 0;
     217                 :           0 :     current_stmt = 0;
     218                 :           0 :   }
     219                 :             : 
     220                 :           0 :   void visit (const Statement &stmt) override
     221                 :             :   {
     222                 :           0 :     switch (stmt.get_kind ())
     223                 :             :       {
     224                 :           0 :         case Statement::Kind::ASSIGNMENT: {
     225                 :             :           // TODO: for unwind, must had hadning for non-panic-only assignements
     226                 :           0 :           issue_write_deep (stmt.get_place ());
     227                 :           0 :           visit_assignment_expr (stmt.get_place (), stmt.get_expr ());
     228                 :           0 :           break;
     229                 :             :         }
     230                 :           0 :         case Statement::Kind::SWITCH: {
     231                 :           0 :           issue_read_move (stmt.get_place ());
     232                 :           0 :           issue_jumps ();
     233                 :             :         }
     234                 :           0 :         break;
     235                 :           0 :         case Statement::Kind::GOTO: {
     236                 :           0 :           issue_jumps ();
     237                 :             :         }
     238                 :           0 :         break;
     239                 :           0 :         case Statement::Kind::RETURN: {
     240                 :           0 :           issue_place_access (RETURN_VALUE_PLACE);
     241                 :           0 :           issue_locals_dealloc ();
     242                 :           0 :           break;
     243                 :             :         }
     244                 :           0 :         case Statement::Kind::STORAGE_DEAD: {
     245                 :           0 :           facts.path_moved_at_base.emplace_back (stmt.get_place (),
     246                 :           0 :                                                  get_current_point_mid ());
     247                 :           0 :           facts.var_defined_at.emplace_back (stmt.get_place (),
     248                 :           0 :                                              get_current_point_mid ());
     249                 :           0 :           break;
     250                 :             :         }
     251                 :           0 :         case Statement::Kind::STORAGE_LIVE: {
     252                 :           0 :           issue_write_deep (stmt.get_place (), true);
     253                 :           0 :           break;
     254                 :             :         }
     255                 :           0 :         case Statement::Kind::USER_TYPE_ASCRIPTION: {
     256                 :           0 :           issue_user_type_constraints (stmt.get_place (), stmt.get_type ());
     257                 :           0 :           break;
     258                 :             :         }
     259                 :           0 :         case Statement::Kind::FAKE_READ: {
     260                 :           0 :           issue_place_access (stmt.get_place ());
     261                 :           0 :           break;
     262                 :             :         }
     263                 :             :       }
     264                 :           0 :   }
     265                 :             : 
     266                 :           0 :   void visit_assignment_expr (PlaceId lhs, AbstractExpr &expr)
     267                 :             :   {
     268                 :           0 :     this->lhs = lhs;
     269                 :           0 :     expr.accept_vis (*this);
     270                 :           0 :     this->lhs = INVALID_PLACE;
     271                 :           0 :   }
     272                 :             : 
     273                 :           0 :   void visit (const InitializerExpr &expr) override
     274                 :             :   {
     275                 :           0 :     sanitize_constrains_at_init (lhs);
     276                 :             : 
     277                 :           0 :     for (auto init_value : expr.get_values ())
     278                 :           0 :       issue_read_move (init_value);
     279                 :           0 :   }
     280                 :             : 
     281                 :           0 :   void visit (const Operator<1> &expr) override
     282                 :             :   {
     283                 :           0 :     sanitize_constrains_at_init (lhs);
     284                 :           0 :     issue_read_move (expr.get_operand<0> ());
     285                 :           0 :   }
     286                 :             : 
     287                 :           0 :   void visit (const Operator<2> &expr) override
     288                 :             :   {
     289                 :           0 :     sanitize_constrains_at_init (lhs);
     290                 :           0 :     issue_read_move (expr.get_operand<0> ());
     291                 :           0 :     issue_read_move (expr.get_operand<1> ());
     292                 :           0 :   }
     293                 :             : 
     294                 :           0 :   void visit (const BorrowExpr &expr) override
     295                 :             :   {
     296                 :           0 :     rust_debug ("\t_%u = BorrowExpr(_%u)", lhs - 1, expr.get_place () - 1);
     297                 :             : 
     298                 :           0 :     auto loan = place_db.get_loans ()[expr.get_loan ()];
     299                 :             : 
     300                 :           0 :     auto &base_place = place_db[expr.get_place ()];
     301                 :           0 :     auto &ref_place = place_db[lhs];
     302                 :             : 
     303                 :           0 :     issue_place_access (expr.get_place ());
     304                 :             : 
     305                 :             :     // See compiler/rustc_borrowck/src/type_check/mod.rs:add_reborrow_constraint
     306                 :           0 :     if (base_place.kind == Place::DEREF)
     307                 :             :       {
     308                 :             :         // Reborrow
     309                 :             : 
     310                 :           0 :         auto &main_loan_place = place_db[base_place.path.parent];
     311                 :           0 :         if (loan.mutability == Mutability::Mut)
     312                 :             :           {
     313                 :           0 :             if (!main_loan_place.tyty->as<TyTy::ReferenceType> ()
     314                 :           0 :                    ->is_mutable ())
     315                 :           0 :               rust_error_at (location,
     316                 :             :                              "Cannot reborrow immutable borrow as mutable");
     317                 :           0 :             issue_loan (expr.get_origin (), expr.get_loan ());
     318                 :             :           }
     319                 :             : 
     320                 :           0 :         push_subset (main_loan_place.regions[0], expr.get_origin ());
     321                 :             :       }
     322                 :             :     else
     323                 :             :       {
     324                 :           0 :         issue_loan (expr.get_origin (), expr.get_loan ());
     325                 :             :       }
     326                 :             : 
     327                 :           0 :     auto loan_regions = base_place.regions.prepend (expr.get_origin ());
     328                 :           0 :     push_subset (ref_place.tyty, loan_regions, ref_place.regions);
     329                 :           0 :   }
     330                 :             : 
     331                 :           0 :   void visit (const Assignment &expr) override
     332                 :             :   {
     333                 :           0 :     rust_debug ("\t_%u = Assignment(_%u) at %u:%u", lhs - 1,
     334                 :             :                 expr.get_rhs () - 1, current_bb, current_stmt);
     335                 :             : 
     336                 :           0 :     issue_read_move (expr.get_rhs ());
     337                 :           0 :     push_place_subset (lhs, expr.get_rhs ());
     338                 :           0 :   }
     339                 :             : 
     340                 :           0 :   void visit (const CallExpr &expr) override
     341                 :             :   {
     342                 :           0 :     rust_debug ("\t_%u = CallExpr(_%u)", lhs - 1, expr.get_callable () - 1);
     343                 :             : 
     344                 :           0 :     auto &return_place = place_db[lhs];
     345                 :           0 :     auto &callable_place = place_db[expr.get_callable ()];
     346                 :           0 :     auto callable_ty = callable_place.tyty->as<TyTy::CallableTypeInterface> ();
     347                 :             : 
     348                 :           0 :     issue_read_move (expr.get_callable ());
     349                 :             : 
     350                 :             :     // Each call needs unique regions.
     351                 :           0 :     auto call_regions = make_fresh_regions (callable_place.regions.size ());
     352                 :             : 
     353                 :           0 :     for (size_t i = 0; i < expr.get_arguments ().size (); ++i)
     354                 :             :       {
     355                 :           0 :         auto arg = expr.get_arguments ().at (i);
     356                 :           0 :         auto arg_regions
     357                 :           0 :           = bind_regions (Resolver::TypeCheckContext::get ()
     358                 :           0 :                             ->get_variance_analysis_ctx ()
     359                 :           0 :                             .query_type_regions (
     360                 :           0 :                               callable_ty->get_param_type_at (i)),
     361                 :           0 :                           call_regions);
     362                 :           0 :         issue_read_move (arg);
     363                 :           0 :         push_subset (place_db[arg].tyty, place_db[arg].regions, arg_regions);
     364                 :           0 :       }
     365                 :             : 
     366                 :             :     // sanitize return regions
     367                 :           0 :     sanitize_constrains_at_init (lhs);
     368                 :             : 
     369                 :           0 :     auto return_regions
     370                 :           0 :       = bind_regions (Resolver::TypeCheckContext::get ()
     371                 :           0 :                         ->get_variance_analysis_ctx ()
     372                 :           0 :                         .query_type_regions (
     373                 :           0 :                           callable_ty->as<TyTy::FnType> ()->get_return_type ()),
     374                 :           0 :                       call_regions);
     375                 :           0 :     push_subset (return_place.tyty, return_regions, return_place.regions);
     376                 :             : 
     377                 :           0 :     issue_jumps ();
     378                 :           0 :   }
     379                 :             : 
     380                 :             : protected: // Statement visitor helpers
     381                 :           0 :   WARN_UNUSED_RESULT const BasicBlock &get_current_bb () const
     382                 :             :   {
     383                 :           0 :     return basic_blocks[current_bb];
     384                 :             :   }
     385                 :             : 
     386                 :             :   WARN_UNUSED_RESULT static Polonius::Point
     387                 :           0 :   get_point (BasicBlockId bb, uint32_t stmt, PointPosition pos)
     388                 :             :   {
     389                 :           0 :     Polonius::Point point = 0;
     390                 :           0 :     point |= (bb << 16);
     391                 :           0 :     point |= (stmt << 1);
     392                 :           0 :     point |= (static_cast<uint8_t> (pos) & 1);
     393                 :           0 :     return point;
     394                 :             :   }
     395                 :             : 
     396                 :           0 :   WARN_UNUSED_RESULT Polonius::Point get_current_point_start () const
     397                 :             :   {
     398                 :           0 :     return get_point (current_bb, current_stmt, PointPosition::START);
     399                 :             :   }
     400                 :             : 
     401                 :           0 :   WARN_UNUSED_RESULT Polonius::Point get_current_point_mid () const
     402                 :             :   {
     403                 :           0 :     return get_point (current_bb, current_stmt, PointPosition::MID);
     404                 :             :   }
     405                 :             : 
     406                 :           0 :   void add_stmt_to_cfg (BasicBlockId bb, uint32_t stmt)
     407                 :             :   {
     408                 :           0 :     if (stmt != 0)
     409                 :             :       {
     410                 :           0 :         facts.cfg_edge.emplace_back (get_point (bb, stmt - 1,
     411                 :             :                                                 PointPosition::MID),
     412                 :           0 :                                      get_point (bb, stmt,
     413                 :             :                                                 PointPosition::START));
     414                 :             :       }
     415                 :             : 
     416                 :           0 :     facts.cfg_edge.emplace_back (get_point (bb, stmt, PointPosition::START),
     417                 :           0 :                                  get_point (bb, stmt, PointPosition::MID));
     418                 :           0 :   }
     419                 :             : 
     420                 :             : protected: // Generic BIR operations.
     421                 :           0 :   void issue_jumps ()
     422                 :             :   {
     423                 :           0 :     for (auto succ : get_current_bb ().successors)
     424                 :           0 :       facts.cfg_edge.emplace_back (get_current_point_mid (),
     425                 :           0 :                                    get_point (succ, 0, PointPosition::START));
     426                 :           0 :   }
     427                 :             : 
     428                 :             :   /* Shallow r/w access */
     429                 :           0 :   void issue_place_access (PlaceId place_id)
     430                 :             :   {
     431                 :           0 :     auto &place = place_db[place_id];
     432                 :             : 
     433                 :           0 :     if (place.is_constant ())
     434                 :             :       return;
     435                 :             : 
     436                 :           0 :     if (place_id != RETURN_VALUE_PLACE)
     437                 :           0 :       facts.path_accessed_at_base.emplace_back (place_id,
     438                 :           0 :                                                 get_current_point_mid ());
     439                 :             : 
     440                 :           0 :     if (place.is_var ())
     441                 :           0 :       facts.var_used_at.emplace_back (place_id, get_current_point_mid ());
     442                 :           0 :     else if (place.is_path ())
     443                 :             :       {
     444                 :           0 :         facts.var_used_at.emplace_back (place_db.get_var (place_id),
     445                 :           0 :                                         get_current_point_mid ());
     446                 :             :       }
     447                 :             :   }
     448                 :             : 
     449                 :             :   /** Deep read access, which consumes the place. */
     450                 :           0 :   void issue_read_move (PlaceId place_id)
     451                 :             :   {
     452                 :           0 :     auto &place = place_db[place_id];
     453                 :             : 
     454                 :           0 :     issue_place_access (place_id);
     455                 :           0 :     if (place.should_be_moved ())
     456                 :             :       {
     457                 :           0 :         issue_move (place_id);
     458                 :             :       }
     459                 :             :     else
     460                 :             :       {
     461                 :           0 :         check_read_for_conflicts (place_id);
     462                 :             :       }
     463                 :           0 :   }
     464                 :             : 
     465                 :           0 :   void issue_write_deep (PlaceId place_id, bool is_init = false)
     466                 :             :   {
     467                 :           0 :     auto &place = place_db[place_id];
     468                 :           0 :     rust_assert (place.is_lvalue () || place.is_rvalue ());
     469                 :             : 
     470                 :           0 :     if (place.is_var ())
     471                 :           0 :       facts.var_defined_at.emplace_back (place_id, get_current_point_mid ());
     472                 :             : 
     473                 :           0 :     if (!is_init)
     474                 :             :       {
     475                 :           0 :         facts.path_assigned_at_base.emplace_back (place_id,
     476                 :           0 :                                                   get_current_point_mid ());
     477                 :           0 :         check_write_for_conflict (place_id);
     478                 :           0 :         kill_borrows_for_place (place_id);
     479                 :             :       }
     480                 :           0 :   }
     481                 :             : 
     482                 :           0 :   void issue_move (PlaceId place_id, bool initial = false)
     483                 :             :   {
     484                 :           0 :     if (!place_db[place_id].should_be_moved ())
     485                 :             :       return;
     486                 :             : 
     487                 :           0 :     facts.path_moved_at_base.emplace_back (
     488                 :           0 :       place_id, initial ? get_point (0, 0, PointPosition::START)
     489                 :           0 :                         : get_current_point_mid ());
     490                 :             : 
     491                 :           0 :     check_move_behind_reference (place_id);
     492                 :             : 
     493                 :           0 :     if (!initial)
     494                 :             :       {
     495                 :           0 :         check_write_for_conflict (place_id);
     496                 :           0 :         kill_borrows_for_place (place_id);
     497                 :             :       }
     498                 :             :   }
     499                 :             : 
     500                 :           0 :   void issue_loan (Polonius::Origin origin, LoanId loan_id)
     501                 :             :   {
     502                 :           0 :     facts.loan_issued_at.emplace_back (origin, loan_id,
     503                 :           0 :                                        get_current_point_mid ());
     504                 :             : 
     505                 :           0 :     check_for_borrow_conficts (place_db.get_loans ()[loan_id].place, loan_id,
     506                 :           0 :                                place_db.get_loans ()[loan_id].mutability);
     507                 :           0 :   }
     508                 :             : 
     509                 :           0 :   void issue_locals_dealloc ()
     510                 :             :   {
     511                 :           0 :     for (LoanId loan_id = 0; loan_id < place_db.get_loans ().size (); ++loan_id)
     512                 :             :       {
     513                 :           0 :         auto &loan = place_db.get_loans ()[loan_id];
     514                 :           0 :         auto loaned_var_id = place_db.get_var (loan.place);
     515                 :           0 :         if (place_db[loaned_var_id].tyty->is<TyTy::ReferenceType> ())
     516                 :           0 :           continue;
     517                 :           0 :         if (loaned_var_id >= first_local)
     518                 :           0 :           facts.loan_invalidated_at.emplace_back (get_current_point_start (),
     519                 :             :                                                   loan_id);
     520                 :             :       }
     521                 :           0 :   }
     522                 :             : 
     523                 :           0 :   void issue_user_type_constraints (PlaceId place_id, TyTy::BaseType *type)
     524                 :             :   {
     525                 :           0 :     auto user_regions = Resolver::TypeCheckContext::get ()
     526                 :           0 :                           ->get_variance_analysis_ctx ()
     527                 :           0 :                           .query_type_regions (type);
     528                 :           0 :     push_subset_user (place_db[place_id].tyty, place_db[place_id].regions,
     529                 :             :                       user_regions);
     530                 :           0 :   }
     531                 :             : 
     532                 :           0 :   void check_read_for_conflicts (PlaceId place_id)
     533                 :             :   {
     534                 :           0 :     place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
     535                 :           0 :       for (auto loan : place_db[id].borrowed_by)
     536                 :             :         {
     537                 :           0 :           if (place_db.get_loans ()[loan].mutability == Mutability::Mut)
     538                 :             :             {
     539                 :           0 :               facts.loan_invalidated_at.emplace_back (
     540                 :           0 :                 get_current_point_start (), loan);
     541                 :             :             }
     542                 :             :         }
     543                 :           0 :     });
     544                 :           0 :     place_db.for_each_path_from_root (place_id, [&] (PlaceId id) {
     545                 :           0 :       for (auto loan : place_db[id].borrowed_by)
     546                 :             :         {
     547                 :           0 :           if (place_db.get_loans ()[loan].mutability == Mutability::Mut)
     548                 :             :             {
     549                 :           0 :               facts.loan_invalidated_at.emplace_back (
     550                 :           0 :                 get_current_point_start (), loan);
     551                 :             :             }
     552                 :             :         }
     553                 :           0 :     });
     554                 :           0 :   }
     555                 :             : 
     556                 :           0 :   void check_write_for_conflict (PlaceId place_id)
     557                 :             :   {
     558                 :           0 :     place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
     559                 :           0 :       for (auto loan : place_db[id].borrowed_by)
     560                 :           0 :         facts.loan_invalidated_at.emplace_back (get_current_point_start (),
     561                 :             :                                                 loan);
     562                 :           0 :     });
     563                 :           0 :     place_db.for_each_path_from_root (place_id, [&] (PlaceId id) {
     564                 :           0 :       for (auto loan : place_db[id].borrowed_by)
     565                 :           0 :         facts.loan_invalidated_at.emplace_back (get_current_point_start (),
     566                 :             :                                                 loan);
     567                 :           0 :     });
     568                 :           0 :   }
     569                 :             : 
     570                 :           0 :   void check_for_borrow_conficts (PlaceId place_id, LoanId loan,
     571                 :             :                                   Mutability mutability)
     572                 :             :   {
     573                 :           0 :     place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
     574                 :           0 :       for (auto other_loan : place_db[id].borrowed_by)
     575                 :             :         {
     576                 :           0 :           if (mutability == Mutability::Imm
     577                 :           0 :               && place_db.get_loans ()[other_loan].mutability
     578                 :             :                    == Mutability::Imm)
     579                 :           0 :             continue;
     580                 :             :           else
     581                 :           0 :             facts.loan_invalidated_at.emplace_back (get_current_point_start (),
     582                 :             :                                                     other_loan);
     583                 :             :         }
     584                 :           0 :     });
     585                 :             : 
     586                 :           0 :     place_db.for_each_path_from_root (place_id, [&] (PlaceId id) {
     587                 :           0 :       for (auto other_loan : place_db[id].borrowed_by)
     588                 :             :         {
     589                 :           0 :           if (mutability == Mutability::Imm
     590                 :           0 :               && place_db.get_loans ()[other_loan].mutability
     591                 :             :                    == Mutability::Imm)
     592                 :           0 :             continue;
     593                 :             :           else
     594                 :           0 :             facts.loan_invalidated_at.emplace_back (get_current_point_start (),
     595                 :             :                                                     other_loan);
     596                 :             :         }
     597                 :           0 :     });
     598                 :           0 :   }
     599                 :             : 
     600                 :           0 :   void check_move_behind_reference (PlaceId place_id)
     601                 :             :   {
     602                 :           0 :     place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
     603                 :           0 :       if (id == place_id)
     604                 :             :         return;
     605                 :           0 :       if (place_db[id].kind == Place::DEREF)
     606                 :           0 :         rust_error_at (location, "Cannot move from behind a reference.");
     607                 :             :     });
     608                 :           0 :   }
     609                 :             : 
     610                 :           0 :   void kill_borrows_for_place (PlaceId place_id)
     611                 :             :   {
     612                 :           0 :     auto &place = place_db[place_id];
     613                 :           0 :     for (auto loan : place.borrowed_by)
     614                 :             :       {
     615                 :             :         // TODO: this is more complicated, see
     616                 :             :         // compiler/rustc_borrowck/src/constraint_generation.rs:176
     617                 :           0 :         facts.loan_killed_at.emplace_back (loan, get_current_point_mid ());
     618                 :             :       }
     619                 :           0 :   }
     620                 :             : 
     621                 :             : protected: // Subset helpers.
     622                 :           0 :   void push_subset (FreeRegion lhs, FreeRegion rhs)
     623                 :             :   {
     624                 :           0 :     rust_debug ("\t\tpush_subset: '?%lu: '?%lu", (unsigned long) lhs,
     625                 :             :                 (unsigned long) rhs);
     626                 :             : 
     627                 :           0 :     facts.subset_base.emplace_back (lhs, rhs, get_current_point_mid ());
     628                 :           0 :   }
     629                 :             : 
     630                 :           0 :   void push_subset_all (FreeRegion lhs, FreeRegion rhs)
     631                 :             :   {
     632                 :           0 :     rust_debug ("\t\tpush_subset_all: '?%lu: '?%lu", (unsigned long) lhs,
     633                 :             :                 (unsigned long) rhs);
     634                 :             : 
     635                 :           0 :     for (auto point : cfg_points_all)
     636                 :           0 :       facts.subset_base.emplace_back (lhs, rhs, point);
     637                 :           0 :   }
     638                 :             : 
     639                 :           0 :   void push_subset (Variance variance, FreeRegion lhs, FreeRegion rhs)
     640                 :             :   {
     641                 :           0 :     if (variance.is_covariant ())
     642                 :           0 :       push_subset (lhs, rhs);
     643                 :           0 :     else if (variance.is_contravariant ())
     644                 :           0 :       push_subset (rhs, lhs);
     645                 :           0 :     else if (variance.is_invariant ())
     646                 :             :       {
     647                 :           0 :         push_subset (lhs, rhs);
     648                 :           0 :         push_subset (rhs, lhs);
     649                 :             :       }
     650                 :           0 :   }
     651                 :             : 
     652                 :           0 :   void push_subset_all (Variance variance, FreeRegion lhs, FreeRegion rhs)
     653                 :             :   {
     654                 :           0 :     if (variance.is_covariant ())
     655                 :           0 :       push_subset_all (lhs, rhs);
     656                 :           0 :     else if (variance.is_contravariant ())
     657                 :           0 :       push_subset_all (rhs, lhs);
     658                 :           0 :     else if (variance.is_invariant ())
     659                 :             :       {
     660                 :           0 :         push_subset_all (lhs, rhs);
     661                 :           0 :         push_subset_all (rhs, lhs);
     662                 :             :       }
     663                 :           0 :   }
     664                 :             : 
     665                 :           0 :   void push_place_subset (PlaceId lhs, PlaceId rhs)
     666                 :             :   {
     667                 :           0 :     auto &lhs_place = place_db[lhs];
     668                 :           0 :     auto &rhs_place = place_db[rhs];
     669                 :             : 
     670                 :           0 :     push_subset (lhs_place.tyty, rhs_place.regions, lhs_place.regions);
     671                 :           0 :   }
     672                 :             : 
     673                 :           0 :   void push_subset (TyTy::BaseType *type, FreeRegions lhs, FreeRegions rhs)
     674                 :             :   {
     675                 :           0 :     auto variances = Resolver::TypeCheckContext::get ()
     676                 :           0 :                        ->get_variance_analysis_ctx ()
     677                 :           0 :                        .query_type_variances (type);
     678                 :           0 :     rust_assert (lhs.size () == rhs.size ());
     679                 :           0 :     rust_assert (lhs.size () == variances.size ());
     680                 :           0 :     for (size_t i = 0; i < lhs.size (); ++i)
     681                 :           0 :       push_subset (variances[i], lhs[i], rhs[i]);
     682                 :           0 :   }
     683                 :             : 
     684                 :           0 :   void push_subset_all (TyTy::BaseType *type, FreeRegions lhs, FreeRegions rhs)
     685                 :             :   {
     686                 :           0 :     auto variances = Resolver::TypeCheckContext::get ()
     687                 :           0 :                        ->get_variance_analysis_ctx ()
     688                 :           0 :                        .query_type_variances (type);
     689                 :           0 :     rust_assert (lhs.size () == rhs.size ());
     690                 :           0 :     rust_assert (lhs.size () == variances.size ());
     691                 :           0 :     for (size_t i = 0; i < lhs.size (); ++i)
     692                 :           0 :       push_subset_all (variances[i], lhs[i], rhs[i]);
     693                 :           0 :   }
     694                 :             : 
     695                 :           0 :   void push_subset_user (TyTy::BaseType *type, FreeRegions free_regions,
     696                 :             :                          std::vector<TyTy::Region> user_regions)
     697                 :             :   {
     698                 :           0 :     auto variances = Resolver::TypeCheckContext::get ()
     699                 :           0 :                        ->get_variance_analysis_ctx ()
     700                 :           0 :                        .query_type_variances (type);
     701                 :           0 :     rust_assert (free_regions.size () == user_regions.size ());
     702                 :           0 :     rust_assert (free_regions.size () == variances.size ());
     703                 :             : 
     704                 :           0 :     for (size_t i = 0; i < free_regions.size (); ++i)
     705                 :             :       {
     706                 :           0 :         if (user_regions[i].is_named ())
     707                 :           0 :           push_subset (variances[i], free_regions[i],
     708                 :           0 :                        {Polonius::Origin (user_regions[i].get_index ())});
     709                 :           0 :         else if (user_regions[i].is_anonymous ())
     710                 :             :           {
     711                 :             :             // IGNORE
     712                 :             :           }
     713                 :             :         else
     714                 :           0 :           rust_internal_error_at (UNKNOWN_LOCATION, "Unexpected region type");
     715                 :             :       }
     716                 :           0 :   }
     717                 :             : 
     718                 :             :   /**
     719                 :             :    * Apply type and lifetime bounds
     720                 :             :    *
     721                 :             :    * For a place we have a list of fresh regions. We need to apply constraints
     722                 :             :    * from type definition to it. First `n` regions belong to the lifetime
     723                 :             :    * parameters of the type. The rest are flatten lifetime parameters of the
     724                 :             :    * type arguments. We walk the type arguments with a offset
     725                 :             :    */
     726                 :           0 :   void sanitize_constrains_at_init (PlaceId place_id)
     727                 :             :   {
     728                 :           0 :     auto &place = place_db[place_id];
     729                 :             : 
     730                 :           0 :     rust_debug ("\tSanitize constraints of %s",
     731                 :             :                 place.tyty->as_string ().c_str ());
     732                 :             : 
     733                 :           0 :     if (auto generic = place.tyty->try_as<TyTy::SubstitutionRef> ())
     734                 :             :       {
     735                 :           0 :         auto &regions = place.regions;
     736                 :           0 :         auto region_end = sanitize_constraints (*generic, 0, regions);
     737                 :           0 :         rust_assert (region_end == regions.size ());
     738                 :             :       }
     739                 :           0 :     else if (place.tyty->is<TyTy::ReferenceType> ())
     740                 :             :       {
     741                 :           0 :         for (auto &region : place.regions)
     742                 :             :           {
     743                 :           0 :             if (region != place.regions[0])
     744                 :           0 :               push_subset (region, place.regions[0]);
     745                 :             :           }
     746                 :             :       }
     747                 :           0 :   }
     748                 :             : 
     749                 :           0 :   size_t sanitize_constraints (const TyTy::BaseType *type, size_t region_start,
     750                 :             :                                const FreeRegions &regions)
     751                 :             :   {
     752                 :           0 :     switch (type->get_kind ())
     753                 :             :       {
     754                 :           0 :       case TyTy::ADT:
     755                 :           0 :         return sanitize_constraints (type->as<const TyTy::ADTType> (),
     756                 :           0 :                                      region_start, regions);
     757                 :             :       case TyTy::STR:
     758                 :             :         return region_start;
     759                 :           0 :       case TyTy::REF:
     760                 :           0 :         return 1
     761                 :             :                + sanitize_constraints (
     762                 :           0 :                  type->as<const TyTy::ReferenceType> ()->get_base (),
     763                 :           0 :                  region_start, regions);
     764                 :           0 :       case TyTy::POINTER:
     765                 :           0 :         return sanitize_constraints (
     766                 :           0 :           type->as<const TyTy::PointerType> ()->get_base (), region_start,
     767                 :           0 :           regions);
     768                 :           0 :       case TyTy::ARRAY:
     769                 :           0 :         return sanitize_constraints (
     770                 :           0 :           type->as<const TyTy::ArrayType> ()->get_element_type (), region_start,
     771                 :           0 :           regions);
     772                 :           0 :       case TyTy::SLICE:
     773                 :           0 :         return sanitize_constraints (
     774                 :           0 :           type->as<const TyTy::SliceType> ()->get_element_type (), region_start,
     775                 :           0 :           regions);
     776                 :           0 :       case TyTy::FNDEF:
     777                 :           0 :         case TyTy::TUPLE: {
     778                 :           0 :           for (auto &field : type->as<const TyTy::TupleType> ()->get_fields ())
     779                 :           0 :             sanitize_constraints (field.get_tyty (), region_start, regions);
     780                 :             :         }
     781                 :             :         break;
     782                 :           0 :       case TyTy::FNPTR:
     783                 :           0 :       case TyTy::PROJECTION:
     784                 :           0 :         return sanitize_constraints (*type->as<const TyTy::SubstitutionRef> (),
     785                 :           0 :                                      region_start, regions);
     786                 :             :       case TyTy::BOOL:
     787                 :             :       case TyTy::CHAR:
     788                 :             :       case TyTy::INT:
     789                 :             :       case TyTy::UINT:
     790                 :             :       case TyTy::FLOAT:
     791                 :             :       case TyTy::USIZE:
     792                 :             :       case TyTy::ISIZE:
     793                 :             :       case TyTy::NEVER:
     794                 :             :       case TyTy::DYNAMIC:
     795                 :             :       case TyTy::CLOSURE:
     796                 :             :       case TyTy::ERROR:
     797                 :             :         return region_start;
     798                 :           0 :       case TyTy::PLACEHOLDER:
     799                 :           0 :       case TyTy::INFER:
     800                 :           0 :       case TyTy::PARAM:
     801                 :           0 :         rust_unreachable ();
     802                 :             :       }
     803                 :           0 :     rust_unreachable ();
     804                 :             :   }
     805                 :             : 
     806                 :           0 :   size_t sanitize_constraints (const TyTy::SubstitutionRef &type,
     807                 :             :                                size_t region_start, const FreeRegions &regions)
     808                 :             :   {
     809                 :           0 :     for (auto constr : type.get_region_constraints ().region_region)
     810                 :             :       {
     811                 :           0 :         rust_assert (constr.first.is_early_bound ());
     812                 :           0 :         rust_assert (constr.second.is_early_bound ());
     813                 :           0 :         auto lhs = constr.first.get_index () + region_start;
     814                 :           0 :         auto rhs = constr.second.get_index () + region_start;
     815                 :           0 :         push_subset (regions[lhs], regions[rhs]);
     816                 :             :       }
     817                 :             : 
     818                 :           0 :     size_t region_end = region_start + type.get_num_lifetime_params ();
     819                 :             : 
     820                 :             :     /*
     821                 :             :      * For type `Foo<'a, T1, T2>`, where `T1 = &'b Vec<&'c i32>` and `T2 = &'d
     822                 :             :      * i32 the regions are `['a, 'b, 'c, 'd]`. The ranges
     823                 :             :      */
     824                 :           0 :     std::vector<size_t> type_param_region_ranges;
     825                 :           0 :     type_param_region_ranges.push_back (region_end);
     826                 :             : 
     827                 :           0 :     for (auto type_param : type.get_substs ())
     828                 :             :       {
     829                 :           0 :         TyTy::SubstitutionArg arg = TyTy::SubstitutionArg::error ();
     830                 :           0 :         bool ok = type.get_used_arguments ().get_argument_for_symbol (
     831                 :           0 :           type_param.get_param_ty (), &arg);
     832                 :           0 :         rust_assert (ok);
     833                 :           0 :         region_end
     834                 :           0 :           = sanitize_constraints (arg.get_tyty (), region_end, regions);
     835                 :           0 :         type_param_region_ranges.push_back (region_end);
     836                 :             :       }
     837                 :             : 
     838                 :             :     /*
     839                 :             :      * For constrain of form: `T: 'a` push outlives with all in range
     840                 :             :      * `indexof(T)..(indexof(T) + 1)`
     841                 :             :      */
     842                 :           0 :     for (auto constr : type.get_region_constraints ().type_region)
     843                 :             :       {
     844                 :           0 :         auto type_param_index_opt
     845                 :           0 :           = type.get_used_arguments ().find_symbol (*constr.first);
     846                 :           0 :         rust_assert (type_param_index_opt.has_value ());
     847                 :           0 :         size_t type_param_index = type_param_index_opt.value ();
     848                 :             : 
     849                 :           0 :         for (size_t i = type_param_region_ranges[type_param_index];
     850                 :           0 :              i < type_param_region_ranges[type_param_index + 1]; ++i)
     851                 :             :           {
     852                 :           0 :             push_subset (regions[i],
     853                 :           0 :                          regions[constr.second.get_index () + region_start]);
     854                 :             :           }
     855                 :             :       }
     856                 :             : 
     857                 :           0 :     return region_end;
     858                 :           0 :   }
     859                 :             : }; // namespace BIR
     860                 :             : 
     861                 :             : } // namespace BIR
     862                 :             : } // namespace Rust
     863                 :             : 
     864                 :             : #endif // RUST_BIR_FACT_COLLECTOR_H
        

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