]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: borrowck: BIR: handle break
authorJakub Dupak <dev@jakubdupak.com>
Wed, 18 Oct 2023 20:54:37 +0000 (22:54 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 18:09:28 +0000 (19:09 +0100)
gcc/rust/ChangeLog:

* checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): Push ctx.
(ExprStmtBuilder::setup_loop): Common loop infractructure setup.
* checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Loop ctx.
* checks/errors/borrowck/rust-bir-builder-internal.h (struct BuilderContext): Loop ctx.

Signed-off-by: Jakub Dupak <dev@jakubdupak.com>
gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h

index 1487c853b49eb1b9b135154d2e91b65a97e4b001..67b98e2254f9bb699d17e55d7c990395a15f1116 100644 (file)
@@ -258,11 +258,45 @@ ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr)
 void
 ExprStmtBuilder::visit (HIR::BlockExpr &block)
 {
+  BasicBlockId end_bb;
+
+  if (block.has_label ())
+    {
+      end_bb = new_bb ();
+      NodeId label
+       = block.get_label ().get_lifetime ().get_mappings ().get_nodeid ();
+      PlaceId label_var = ctx.place_db.add_temporary (lookup_type (block));
+      ctx.loop_and_label_stack.push_back ({false, label, label_var, end_bb, 0});
+    }
+
+  bool unreachable = false;
   for (auto &stmt : block.get_statements ())
     {
+      if (unreachable)
+       break;
       stmt->accept_vis (*this);
+      if (ctx.get_current_bb ().is_terminated ())
+       unreachable = true;
+    }
+
+  if (block.has_label ())
+    {
+      auto label_info = ctx.loop_and_label_stack.back ();
+      if (block.has_expr () && !unreachable)
+       {
+         push_assignment (label_info.label_var,
+                          visit_expr (*block.get_final_expr ()));
+       }
+      if (!ctx.get_current_bb ().is_terminated ())
+       {
+         add_jump_to (end_bb);
+       }
+      ctx.current_bb = end_bb;
+      ctx.loop_and_label_stack.pop_back ();
+
+      return_place (label_info.label_var);
     }
-  if (block.has_expr ())
+  else if (block.has_expr () && !unreachable)
     {
       return_place (visit_expr (*block.get_final_expr ()));
     }
@@ -290,25 +324,36 @@ ExprStmtBuilder::visit (HIR::ContinueExpr &cont)
 void
 ExprStmtBuilder::visit (HIR::BreakExpr &brk)
 {
-  //  BuilderContext::LabelledBlockCtx block_ctx{};
-  //  NodeId label = UNKNOWN_NODEID;
-  //  if (brk.has_label ())
-  //    {
-  //      if (!resolve_label (brk.get_label (), label))
-  //   return;
-  //    }
-  //  if (!find_block_ctx (label, block_ctx))
-  //    {
-  //      rust_error_at (brk.get_locus (), "unresolved labelled block");
-  //    }
-  //
-  //  if (brk.has_break_expr ())
-  //    {
-  //      brk.get_expr ()->accept_vis (*this);
-  //      push_assignment (block_ctx.label_var, new Operator<1> ({translated}));
-  //    }
-  //
-  //  add_jump_to (block_ctx.break_bb);
+  BuilderContext::LoopAndLabelInfo info;
+  if (brk.has_label ())
+    {
+      NodeId label = resolve_label (brk.get_label ());
+      auto lookup
+       = std::find_if (ctx.loop_and_label_stack.rbegin (),
+                       ctx.loop_and_label_stack.rend (),
+                       [label] (const BuilderContext::LoopAndLabelInfo &info) {
+                         return info.label == label;
+                       });
+      rust_assert (lookup != ctx.loop_and_label_stack.rend ());
+      info = *lookup;
+    }
+  else
+    {
+      auto lookup
+       = std::find_if (ctx.loop_and_label_stack.rbegin (),
+                       ctx.loop_and_label_stack.rend (),
+                       [] (const BuilderContext::LoopAndLabelInfo &info) {
+                         return info.is_loop;
+                       });
+      rust_assert (lookup != ctx.loop_and_label_stack.rend ());
+      info = *lookup;
+    }
+  if (brk.has_break_expr ())
+    {
+      push_assignment (info.label_var, visit_expr (*brk.get_expr ()));
+    }
+  add_jump_to (info.break_bb);
+  // No code allowed after break. No BB starts - would be empty.
 }
 
 void
@@ -370,60 +415,87 @@ ExprStmtBuilder::visit (HIR::UnsafeBlockExpr &expr)
   rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported");
 }
 
+BuilderContext::LoopAndLabelInfo &
+ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr)
+{
+  NodeId label = (expr.has_loop_label ())
+                  ? resolve_label (expr.get_loop_label ())
+                  : UNKNOWN_NODEID;
+  PlaceId label_var = ctx.place_db.add_temporary (lookup_type (expr));
+
+  BasicBlockId continue_bb = new_bb ();
+  BasicBlockId break_bb = new_bb ();
+  ctx.loop_and_label_stack.push_back (
+    {true, label, label_var, break_bb, continue_bb});
+  return ctx.loop_and_label_stack.back ();
+}
+
 void
 ExprStmtBuilder::visit (HIR::LoopExpr &expr)
 {
-  //  PlaceId label_var = ctx.place_db.add_temporary (nullptr);
-  //  NodeId label;
-  //  if (!resolve_label (expr.get_loop_label (), label))
-  //    return;
-  //  ctx.label_place_map.emplace (label, label_var);
-  //
-  //  expr.get_loop_block ()->accept_vis (*this);
-  //
-  //  translated = label_var;
+  auto loop = setup_loop (expr);
+
+  add_jump_to (loop.continue_bb);
+
+  ctx.current_bb = loop.continue_bb;
+  (void) visit_expr (*expr.get_loop_block ());
+  add_jump_to (loop.continue_bb);
+
+  ctx.current_bb = loop.break_bb;
 }
+
 void
 ExprStmtBuilder::visit (HIR::WhileLoopExpr &expr)
 {
-  //  // TODO: Desugar in AST->HIR ???
-  //  PlaceId label_var = ctx.place_db.add_temporary (nullptr);
-  //  NodeId label;
-  //  if (!resolve_label (expr.get_loop_label (), label))
-  //    return;
-  //  ctx.label_place_map.emplace (label, label_var);
-  //
-  //  expr.get_predicate_expr ()->accept_vis (*this);
-  //
-  //  expr.get_loop_block ()->accept_vis (*this);
-  //
-  //  translated = label_var;
+  auto loop = setup_loop (expr);
+
+  add_jump_to (loop.continue_bb);
+
+  ctx.current_bb = loop.continue_bb;
+  auto cond_val = visit_expr (*expr.get_predicate_expr ());
+  auto body_bb = new_bb ();
+  push_switch (cond_val, {body_bb, loop.break_bb});
+
+  ctx.current_bb = body_bb;
+  (void) visit_expr (*expr.get_loop_block ());
+  add_jump_to (loop.continue_bb);
+
+  ctx.current_bb = loop.break_bb;
 }
+
 void
 ExprStmtBuilder::visit (HIR::WhileLetLoopExpr &expr)
 {
   // TODO: Desugar in AST->HIR
+  rust_sorry_at (expr.get_locus (), "while let loops are not yet supported");
 }
+
 void
 ExprStmtBuilder::visit (HIR::IfExpr &expr)
 {
   // If without else cannot return a non-unit value (see [E0317]).
 
+  if (expr.get_if_block ()->statements.empty ())
+    return;
+
   push_switch (visit_expr (*expr.get_if_condition ()));
   BasicBlockId if_block = ctx.current_bb;
 
   ctx.current_bb = new_bb ();
+  BasicBlockId then_start_block = ctx.current_bb;
   (void) visit_expr (*expr.get_if_block ());
-  BasicBlockId then_block = ctx.current_bb;
+  BasicBlockId then_end_block = ctx.current_bb;
 
   ctx.current_bb = new_bb ();
   BasicBlockId final_block = ctx.current_bb;
   return_unit (expr);
 
   // Jumps are added at the end to match rustc MIR order for easier comparison.
-  add_jump (if_block, then_block);
+  add_jump (if_block, then_start_block);
   add_jump (if_block, final_block);
-  add_jump (then_block, final_block);
+
+  if (!ctx.basic_blocks[then_end_block].is_terminated ())
+    add_jump (then_end_block, final_block);
 }
 
 void
@@ -451,8 +523,11 @@ ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
   // Jumps are added at the end to match rustc MIR order for easier comparison.
   add_jump (if_block, then_block);
   add_jump (if_block, else_block);
-  add_jump (then_block, final_block);
-  add_jump (else_block, final_block);
+
+  if (!ctx.basic_blocks[then_block].is_terminated ())
+    add_jump (then_block, final_block);
+  if (!ctx.basic_blocks[else_block].is_terminated ())
+    add_jump (else_block, final_block);
 }
 void
 ExprStmtBuilder::visit (HIR::IfLetExpr &expr)
@@ -573,6 +648,5 @@ ExprStmtBuilder::visit (HIR::ExprStmt &stmt)
 {
   (void) visit_expr (*stmt.get_expr ());
 }
-
 } // namespace BIR
 } // namespace Rust
\ No newline at end of file
index f46cba5f9684fbae1bb8a91163e5594cb778010c..e5707c31f8d3a0f8e5301da28c5911e18a7b2302 100644 (file)
@@ -46,6 +46,8 @@ private:
     return result;
   }
 
+  BuilderContext::LoopAndLabelInfo &setup_loop (HIR::BaseLoopExpr &expr);
+
 protected: // Expr
   // TODO: test when compiles
   void visit (HIR::ClosureExpr &expr) override;
index 48116d8c351cc3c5b4aa59878ec00fc93193a557..ef48cba7b80bc11c798dd9f3b4787474e165d4f1 100644 (file)
@@ -55,12 +55,21 @@ public:
 
 struct BuilderContext
 {
-  struct LabelledBlockCtx
+  struct LoopAndLabelInfo
   {
-    NodeId label; // UNKNOWN_NODEID if no label
-    PlaceId label_var;
+    bool is_loop;      // Loop or labelled block
+    NodeId label;      // UNKNOWN_NODEID if no label (loop)
+    PlaceId label_var; // For break with value.
     BasicBlockId break_bb;
     BasicBlockId continue_bb; // Only valid for loops
+
+    LoopAndLabelInfo (bool is_loop = false, NodeId label = UNKNOWN_NODEID,
+                     PlaceId label_var = INVALID_PLACE,
+                     BasicBlockId break_bb = INVALID_BB,
+                     BasicBlockId continue_bb = INVALID_BB)
+      : is_loop (is_loop), label (label), label_var (label_var),
+       break_bb (break_bb), continue_bb (continue_bb)
+    {}
   };
 
   // Context
@@ -83,7 +92,7 @@ struct BuilderContext
    */
   std::unordered_map<NodeId, PlaceId> label_place_map;
 
-  std::vector<LabelledBlockCtx> loop_stack;
+  std::vector<LoopAndLabelInfo> loop_and_label_stack;
 
 public:
   BuilderContext ()
@@ -115,6 +124,18 @@ public:
       }
     rust_unreachable ();
   };
+
+  const LoopAndLabelInfo &lookup_label (NodeId label)
+  {
+    auto label_match = [label] (const LoopAndLabelInfo &info) {
+      return info.label != UNKNOWN_NODEID && info.label == label;
+    };
+
+    auto found = std::find_if (loop_and_label_stack.rbegin (),
+                              loop_and_label_stack.rend (), label_match);
+    rust_assert (found != loop_and_label_stack.rend ());
+    return *found;
+  }
 };
 
 // Common infrastructure for building BIR from HIR.
@@ -195,10 +216,13 @@ protected:
     push_assignment (tmp, rhs);
   }
 
-  void push_switch (PlaceId switch_val)
+  void push_switch (PlaceId switch_val,
+                   std::initializer_list<BasicBlockId> destinations = {})
   {
     ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH,
                                                   switch_val);
+    ctx.get_current_bb ().successors.insert (
+      ctx.get_current_bb ().successors.end (), destinations);
   }
 
   void push_storage_dead (PlaceId place)
@@ -235,15 +259,14 @@ protected:
   void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); }
 
 protected:
-  template <typename T> bool resolve_label (T &label, NodeId &resolved_label)
+  template <typename T> NodeId resolve_label (T &expr)
   {
-    if (!ctx.resolver.lookup_resolved_label (
-         label.get_mappings ().get_nodeid (), &resolved_label))
-      {
-       rust_error_at (label.get_locus (), "unresolved label");
-       return false;
-      }
-    return true;
+    NodeId resolved_label;
+    bool ok
+      = ctx.resolver.lookup_resolved_label (expr.get_mappings ().get_nodeid (),
+                                           &resolved_label);
+    rust_assert (ok);
+    return resolved_label;
   }
 
   template <typename T>
@@ -261,21 +284,22 @@ protected:
     return true;
   }
 
-  bool find_block_ctx (NodeId label, BuilderContext::LabelledBlockCtx &block)
+  bool find_block_ctx (NodeId label, BuilderContext::LoopAndLabelInfo &block)
   {
-    if (ctx.loop_stack.empty ())
+    if (ctx.loop_and_label_stack.empty ())
       return false;
     if (label == UNKNOWN_NODEID)
       {
-       block = ctx.loop_stack.back ();
+       block = ctx.loop_and_label_stack.back ();
        return true;
       }
     auto found
-      = std::find_if (ctx.loop_stack.rbegin (), ctx.loop_stack.rend (),
-                     [&label] (const BuilderContext::LabelledBlockCtx &block) {
+      = std::find_if (ctx.loop_and_label_stack.rbegin (),
+                     ctx.loop_and_label_stack.rend (),
+                     [&label] (const BuilderContext::LoopAndLabelInfo &block) {
                        return block.label == label;
                      });
-    if (found == ctx.loop_stack.rend ())
+    if (found == ctx.loop_and_label_stack.rend ())
       return false;
     block = *found;
     return true;
@@ -318,8 +342,8 @@ protected:
       }
   }
 
-  /** Dereferences the `translated` place until it is at most one reference and
-   * return the base type. */
+  /** Dereferences the `translated` place until it is at most one reference
+   * and return the base type. */
   TyTy::BaseType *autoderef (PlaceId &place)
   {
     auto ty = ctx.place_db[place].tyty;