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

* Make-lang.in: Compile BIR expr visitor.
* checks/errors/borrowck/rust-borrow-checker.cc (BorrowChecker::go): Use BIR builder.
* rust-session-manager.cc (Session::compile_crate): Run borrow checker.
* checks/errors/borrowck/rust-bir-builder-expr-stmt.cc: New file.
* checks/errors/borrowck/rust-bir-builder-expr-stmt.h: New file.
* checks/errors/borrowck/rust-bir-builder-internal.h: New file.
* checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: New file.
* checks/errors/borrowck/rust-bir-builder-pattern.h: New file.
* checks/errors/borrowck/rust-bir-builder-struct.h: New file.
* checks/errors/borrowck/rust-bir-builder.h: New file.

Signed-off-by: Jakub Dupak <dev@jakubdupak.com>
gcc/rust/Make-lang.in
gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-bir-builder.h [new file with mode: 0644]
gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc
gcc/rust/rust-session-manager.cc

index 5be223ef8e956ca68caa863d9c6c6c916d04c846..d99d25ce97de8c6fbc5712181dd02844cde7ecd0 100644 (file)
@@ -149,6 +149,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-enumitem.o \
     rust/rust-hir-type-check-implitem.o \
     rust/rust-borrow-checker.o \
+    rust/rust-bir-builder-expr-stmt.o \
     rust/rust-hir-dot-operator.o \
     rust/rust-hir-path-probe.o \
     rust/rust-type-util.o \
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
new file mode 100644 (file)
index 0000000..1487c85
--- /dev/null
@@ -0,0 +1,578 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If
+// not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-bir-builder-expr-stmt.h"
+#include "rust-bir-builder-lazyboolexpr.h"
+#include "rust-bir-builder-pattern.h"
+#include "rust-bir-builder-struct.h"
+
+namespace Rust {
+namespace BIR {
+
+void
+ExprStmtBuilder::visit (HIR::ClosureExpr &expr)
+{
+  auto closure_ty = lookup_type (expr)->as<TyTy::ClosureType> ();
+  std::vector<PlaceId> captures;
+  for (auto &capture : closure_ty->get_captures ())
+    {
+      captures.push_back (ctx.place_db.lookup_variable (capture));
+    }
+
+  // Not a coercion site.
+  return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::StructExprStructFields &fields)
+{
+  auto struct_ty
+    = lookup_type (fields)->as<TyTy::ADTType> ()->get_variants ().at (0);
+  auto init_values = StructBuilder (ctx, struct_ty).build (fields);
+  return_expr (new InitializerExpr (std::move (init_values)),
+              lookup_type (fields));
+}
+
+void
+ExprStmtBuilder::visit (HIR::StructExprStruct &expr)
+{
+  // There is no way to modify empty struct, which makes them constant.
+  return_place (ctx.place_db.get_constant (lookup_type (expr)));
+}
+
+void
+ExprStmtBuilder::visit (HIR::LiteralExpr &expr)
+{
+  // Different literal values of the same type are not distinguished.
+  return_place (ctx.place_db.get_constant (lookup_type (expr)));
+}
+
+void
+ExprStmtBuilder::visit (HIR::BorrowExpr &expr)
+{
+  auto operand = visit_expr (*expr.get_expr ());
+  return_expr (new BorrowExpr (operand), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::DereferenceExpr &expr)
+{
+  auto operand = visit_expr (*expr.get_expr ());
+  return_place (operand);
+}
+
+void
+ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr)
+{
+  rust_sorry_at (expr.get_locus (), "error propagation is not supported");
+}
+
+void
+ExprStmtBuilder::visit (HIR::NegationExpr &expr)
+{
+  PlaceId operand = visit_expr (*expr.get_expr ());
+  return_expr (new Operator<1> ({operand}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::ArithmeticOrLogicalExpr &expr)
+{
+  PlaceId lhs = visit_expr (*expr.get_lhs ());
+  PlaceId rhs = visit_expr (*expr.get_rhs ());
+  return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::ComparisonExpr &expr)
+{
+  PlaceId lhs = visit_expr (*expr.get_lhs ());
+  PlaceId rhs = visit_expr (*expr.get_rhs ());
+  return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr)
+{
+  return_place (LazyBooleanExprBuilder (ctx).build (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::TypeCastExpr &expr)
+{
+  return_place (visit_expr (*expr.get_expr ()));
+}
+
+void
+ExprStmtBuilder::visit (HIR::AssignmentExpr &expr)
+{
+  auto lhs = visit_expr (*expr.get_lhs ());
+  auto rhs = visit_expr (*expr.get_rhs ());
+  push_assignment (lhs, rhs);
+}
+
+void
+ExprStmtBuilder::visit (HIR::CompoundAssignmentExpr &expr)
+{
+  auto lhs = visit_expr (*expr.get_lhs ());
+  auto rhs = visit_expr (*expr.get_rhs ());
+  push_assignment (lhs, new Operator<2> ({lhs, rhs}));
+  // TODO: (philip) nicer unit?
+  return_place (ctx.place_db.get_constant (lookup_type (expr)));
+}
+
+void
+ExprStmtBuilder::visit (HIR::GroupedExpr &expr)
+{
+  // Uses accept_vis directly to avoid creating n new temporary.
+  expr.get_expr_in_parens ()->accept_vis (*this);
+}
+
+void
+ExprStmtBuilder::visit (HIR::ArrayExpr &expr)
+{
+  switch (expr.get_internal_elements ()->get_array_expr_type ())
+    {
+      case HIR::ArrayElems::VALUES: {
+       auto init_values = visit_list ((static_cast<HIR::ArrayElemsValues *> (
+                                         expr.get_internal_elements ().get ()))
+                                        ->get_values ());
+       return_expr (new InitializerExpr (std::move (init_values)),
+                    lookup_type (expr));
+       break;
+      }
+      case HIR::ArrayElems::COPIED: {
+       auto init = visit_expr (*(static_cast<HIR::ArrayElemsCopied *> (
+                                   expr.get_internal_elements ().get ()))
+                                  ->get_elem_to_copy ());
+       return_expr (new InitializerExpr ({init}), lookup_type (expr));
+       break;
+      }
+    }
+}
+
+void
+ExprStmtBuilder::visit (HIR::ArrayIndexExpr &expr)
+{
+  auto lhs = visit_expr (*expr.get_array_expr ());
+  auto rhs = visit_expr (*expr.get_index_expr ());
+  // The Index is not tracked in BIR.
+  (void) rhs;
+  return_place (
+    ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs));
+}
+
+void
+ExprStmtBuilder::visit (HIR::TupleExpr &expr)
+{
+  std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ());
+  if (std::any_of (init_values.begin (), init_values.end (),
+                  [this] (PlaceId id) {
+                    return ctx.place_db[id].lifetime.has_lifetime ();
+                  }))
+    {
+      ctx.place_db[expr_return_place].lifetime
+       = {ctx.lifetime_interner.get_anonymous ()};
+    }
+  return_expr (new InitializerExpr (std::move (init_values)),
+              lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::TupleIndexExpr &expr)
+{
+  auto tuple = visit_expr (*expr.get_tuple_expr ());
+  return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
+                                                lookup_type (expr), tuple,
+                                                expr.get_tuple_index ()));
+}
+
+void
+ExprStmtBuilder::visit (HIR::CallExpr &expr)
+{
+  PlaceId fn = visit_expr (*expr.get_fnexpr ());
+  std::vector<PlaceId> arguments = visit_list (expr.get_arguments ());
+
+  TyTy::BaseType *call_type = ctx.place_db[fn].tyty;
+  if (auto fn_type = call_type->try_as<TyTy::FnType> ())
+    {
+      for (size_t i = 0; i < fn_type->get_params ().size (); ++i)
+       {
+         coercion_site (arguments[i], fn_type->get_params ()[i].second);
+       }
+    }
+  else if (auto fn_ptr_type = call_type->try_as<TyTy::FnPtr> ())
+    {
+      for (size_t i = 0; i < fn_ptr_type->get_params ().size (); ++i)
+       {
+         coercion_site (arguments[i],
+                        fn_ptr_type->get_params ()[i].get_tyty ());
+       }
+    }
+  else
+    {
+      rust_unreachable ();
+    }
+
+  return_expr (new CallExpr (fn, std::move (arguments)), lookup_type (expr),
+              true);
+}
+
+void
+ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr)
+{
+  auto receiver = visit_expr (*expr.get_receiver_expr ());
+  auto type = autoderef (receiver);
+  rust_assert (type->get_kind () == TyTy::ADT);
+  auto adt = type->as<TyTy::ADTType> ();
+  rust_assert (!adt->is_enum ());
+  rust_assert (adt->number_of_variants () == 1);
+  TyTy::VariantDef *variant = adt->get_variants ().at (0);
+
+  TyTy::StructFieldType *field_ty = nullptr;
+  size_t field_index = 0;
+  bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
+                                  &field_ty, &field_index);
+  rust_assert (ok);
+
+  return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
+                                                field_ty->get_field_type (),
+                                                receiver, field_index));
+}
+
+void
+ExprStmtBuilder::visit (HIR::BlockExpr &block)
+{
+  for (auto &stmt : block.get_statements ())
+    {
+      stmt->accept_vis (*this);
+    }
+  if (block.has_expr ())
+    {
+      return_place (visit_expr (*block.get_final_expr ()));
+    }
+}
+
+void
+ExprStmtBuilder::visit (HIR::ContinueExpr &cont)
+{
+  //  BuilderContext::LabelledBlockCtx loop_ctx;
+  //  NodeId label = UNKNOWN_NODEID;
+  //  if (cont.has_label ())
+  //    {
+  //      if (!resolve_label (cont.get_label (), label))
+  //   return;
+  //    }
+  //
+  //  if (!find_block_ctx (label, loop_ctx))
+  //    {
+  //      rust_error_at (cont.get_locus (), "unresolved loop label");
+  //    }
+  //
+  //  add_jump_to (loop_ctx.continue_bb);
+}
+
+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);
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeFromToExpr &range)
+{
+  auto from = visit_expr (*range.get_from_expr ());
+  auto to = visit_expr (*range.get_to_expr ());
+  return_expr (new InitializerExpr ({from, to}), lookup_type (range));
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeFromExpr &expr)
+{
+  auto from = visit_expr (*expr.get_from_expr ());
+  return_expr (new InitializerExpr ({from}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeToExpr &expr)
+{
+  auto to = visit_expr (*expr.get_to_expr ());
+  return_expr (new InitializerExpr ({to}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeFullExpr &expr)
+{
+  return_expr (new InitializerExpr ({}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeFromToInclExpr &expr)
+{
+  auto from = visit_expr (*expr.get_from_expr ());
+  auto to = visit_expr (*expr.get_to_expr ());
+  return_expr (new InitializerExpr ({from, to}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr)
+{
+  auto to = visit_expr (*expr.get_to_expr ());
+  return_expr (new InitializerExpr ({to}), lookup_type (expr));
+}
+
+void
+ExprStmtBuilder::visit (HIR::ReturnExpr &ret)
+{
+  if (ret.has_return_expr ())
+    {
+      push_assignment (RETURN_VALUE_PLACE, visit_expr (*ret.get_expr ()));
+    }
+  ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN);
+}
+
+void
+ExprStmtBuilder::visit (HIR::UnsafeBlockExpr &expr)
+{
+  rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported");
+}
+
+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;
+}
+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;
+}
+void
+ExprStmtBuilder::visit (HIR::WhileLetLoopExpr &expr)
+{
+  // TODO: Desugar in AST->HIR
+}
+void
+ExprStmtBuilder::visit (HIR::IfExpr &expr)
+{
+  // If without else cannot return a non-unit value (see [E0317]).
+
+  push_switch (visit_expr (*expr.get_if_condition ()));
+  BasicBlockId if_block = ctx.current_bb;
+
+  ctx.current_bb = new_bb ();
+  (void) visit_expr (*expr.get_if_block ());
+  BasicBlockId then_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, final_block);
+  add_jump (then_block, final_block);
+}
+
+void
+ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
+{
+  PlaceId result = ctx.place_db.add_temporary (lookup_type (expr));
+
+  push_switch (visit_expr (*expr.get_if_condition ()));
+  BasicBlockId if_block = ctx.current_bb;
+
+  ctx.current_bb = new_bb ();
+  auto then_res = visit_expr (*expr.get_if_block ());
+  push_assignment (result, then_res);
+  BasicBlockId then_block = ctx.current_bb;
+
+  ctx.current_bb = new_bb ();
+  auto else_res = visit_expr (*expr.get_else_block ());
+  push_assignment (result, else_res);
+  BasicBlockId else_block = ctx.current_bb;
+
+  ctx.current_bb = new_bb ();
+  BasicBlockId final_block = ctx.current_bb;
+  return_place (result);
+
+  // 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);
+}
+void
+ExprStmtBuilder::visit (HIR::IfLetExpr &expr)
+{
+  rust_sorry_at (expr.get_locus (), "if let expressions are not supported");
+}
+void
+ExprStmtBuilder::visit (HIR::IfLetExprConseqElse &expr)
+{
+  rust_sorry_at (expr.get_locus (), "if let expressions are not supported");
+}
+void
+ExprStmtBuilder::visit (HIR::MatchExpr &expr)
+{
+  //  // TODO
+  //  expr.get_scrutinee_expr ()->accept_vis (*this);
+  //  PlaceId scrutinee = translated;
+  //
+  //  BasicBlockId final_bb = new_bb ();
+  //
+  //  BasicBlockId next_case_bb = new_bb ();
+  //  for (auto &match_case : expr.get_match_cases ())
+  //    {
+  //      BasicBlockId body_bb = new_bb ();
+  //
+  //      BasicBlockId next_pattern_bb = new_bb ();
+  //      for (auto &pat : match_case.get_arm ().get_patterns ())
+  //   {
+  //     compile_pattern_validation (*pat, scrutinee);
+  //     push_switch (translated);
+  //     add_jump_to (next_pattern_bb);
+  //     start_new_subsequent_bb ();
+  //     compile_pattern_bindings (*pat, scrutinee);
+  //     add_jump_to (body_bb);
+  //
+  //     ctx.current_bb = next_pattern_bb;
+  //     next_pattern_bb = new_bb ();
+  //   }
+  //      ctx.current_bb = next_pattern_bb;
+  //      // No pattern matched, go to the next case.
+  //      add_jump_to (next_case_bb);
+  //
+  //      ctx.current_bb = body_bb;
+  //      match_case.get_expr ()->accept_vis (*this);
+  //      add_jump_to (final_bb);
+  //
+  //      ctx.current_bb = next_case_bb;
+  //      next_case_bb = new_bb ();
+  //    }
+  //  add_jump_to (final_bb);
+  //
+  //  ctx.current_bb = final_bb;
+}
+
+void
+ExprStmtBuilder::visit (HIR::AwaitExpr &expr)
+{
+  rust_sorry_at (expr.get_locus (), "await expressions are not supported");
+}
+
+void
+ExprStmtBuilder::visit (HIR::AsyncBlockExpr &expr)
+{
+  rust_sorry_at (expr.get_locus (), "async blocks are not supported");
+}
+
+void
+ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr)
+{
+  PlaceId result;
+  // Note: Type is only stored for the expr, not the segment.
+  bool ok = resolve_variable (expr.get_final_segment (), result);
+  rust_assert (ok);
+  return_place (result);
+}
+
+void
+ExprStmtBuilder::visit (HIR::PathInExpression &expr)
+{
+  PlaceId result;
+  // Note: Type is only stored for the expr, not the segment.
+  bool ok = resolve_variable (expr.get_final_segment (), result);
+  rust_assert (ok);
+  return_place (result);
+}
+
+void
+ExprStmtBuilder::visit (HIR::LetStmt &stmt)
+{
+  if (stmt.has_init_expr ())
+    {
+      auto init = visit_expr (*stmt.get_init_expr ());
+      PatternBindingBuilder (ctx, init, stmt.get_type ().get ())
+       .go (*stmt.get_pattern ());
+    }
+  else if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER)
+    {
+      auto var = declare_variable (stmt.get_pattern ()->get_mappings ());
+      auto &var_place = ctx.place_db[var];
+      if (var_place.tyty->get_kind () == TyTy::REF)
+       {
+         auto p_type = tl::optional<HIR::ReferenceType *> (
+           static_cast<HIR::ReferenceType *> (stmt.get_type ().get ()));
+         var_place.lifetime = ctx.lookup_lifetime (
+           p_type.map (&HIR::ReferenceType::get_lifetime));
+       }
+      return;
+    }
+  else
+    {
+      // TODO
+      rust_sorry_at (stmt.get_locus (), "pattern matching in let statements");
+    }
+}
+
+void
+ExprStmtBuilder::visit (HIR::ExprStmt &stmt)
+{
+  (void) visit_expr (*stmt.get_expr ());
+}
+
+} // namespace BIR
+} // namespace Rust
\ No newline at end of file
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
new file mode 100644 (file)
index 0000000..f46cba5
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_EXPR_H
+#define RUST_BIR_BUILDER_EXPR_H
+
+#include "rust-hir-visitor.h"
+#include "rust-bir-builder-internal.h"
+
+namespace Rust {
+namespace BIR {
+
+class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor
+{
+  PlaceId expr_return_place = INVALID_PLACE;
+
+public:
+  explicit ExprStmtBuilder (BuilderContext &ctx) : AbstractExprBuilder (ctx) {}
+
+  PlaceId build (HIR::Expr &expr) { return visit_expr (expr); }
+
+private:
+  template <typename T>
+  std::vector<PlaceId> visit_list (std::vector<std::unique_ptr<T>> &list)
+  {
+    std::vector<PlaceId> result;
+    for (auto &elem : list)
+      {
+       result.push_back (visit_expr (*elem));
+      }
+    return result;
+  }
+
+protected: // Expr
+  // TODO: test when compiles
+  void visit (HIR::ClosureExpr &expr) override;
+  void visit (HIR::StructExprStructFields &fields) override;
+  void visit (HIR::StructExprStruct &expr) override;
+  void visit (HIR::LiteralExpr &expr) override;
+  void visit (HIR::BorrowExpr &expr) override;
+  void visit (HIR::DereferenceExpr &expr) override;
+  // TODO: desugar in AST->HIR
+  void visit (HIR::ErrorPropagationExpr &expr) override;
+  void visit (HIR::NegationExpr &expr) override;
+  void visit (HIR::ArithmeticOrLogicalExpr &expr) override;
+  void visit (HIR::ComparisonExpr &expr) override;
+  void visit (HIR::LazyBooleanExpr &expr) override;
+  void visit (HIR::TypeCastExpr &expr) override;
+  void visit (HIR::AssignmentExpr &expr) override;
+  void visit (HIR::CompoundAssignmentExpr &expr) override;
+  void visit (HIR::GroupedExpr &expr) override;
+  void visit (HIR::ArrayExpr &expr) override;
+  void visit (HIR::ArrayIndexExpr &expr) override;
+  void visit (HIR::TupleExpr &expr) override;
+  void visit (HIR::TupleIndexExpr &expr) override;
+  void visit (HIR::CallExpr &expr) override;
+  void visit (HIR::MethodCallExpr &expr) override {}
+  void visit (HIR::FieldAccessExpr &expr) override;
+  void visit (HIR::BlockExpr &block) override;
+  void visit (HIR::ContinueExpr &cont) override;
+  void visit (HIR::BreakExpr &brk) override;
+  void visit (HIR::RangeFromToExpr &range) override;
+  void visit (HIR::RangeFromExpr &expr) override;
+  void visit (HIR::RangeToExpr &expr) override;
+  void visit (HIR::RangeFullExpr &expr) override;
+  void visit (HIR::RangeFromToInclExpr &expr) override;
+  void visit (HIR::RangeToInclExpr &expr) override;
+  void visit (HIR::ReturnExpr &ret) override;
+  void visit (HIR::UnsafeBlockExpr &expr) override;
+  void visit (HIR::LoopExpr &expr) override;
+  void visit (HIR::WhileLoopExpr &expr) override;
+  void visit (HIR::WhileLetLoopExpr &expr) override;
+  void visit (HIR::IfExpr &expr) override;
+  void visit (HIR::IfExprConseqElse &expr) override;
+
+  void visit (HIR::IfLetExpr &expr) override;
+  void visit (HIR::IfLetExprConseqElse &expr) override;
+  void visit (HIR::MatchExpr &expr) override;
+  void visit (HIR::AwaitExpr &expr) override;
+  void visit (HIR::AsyncBlockExpr &expr) override;
+
+  // Nodes not containing executable code. Nothing to do.
+  void visit (HIR::QualifiedPathInExpression &expr) override;
+  void visit (HIR::PathInExpression &expr) override;
+
+protected: // Handled by other visitors
+  void visit (HIR::StructExprFieldIdentifier &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructExprFieldIdentifierValue &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructExprFieldIndexValue &field) override
+  {
+    rust_unreachable ();
+  }
+
+protected: // Stmt
+  void visit (HIR::LetStmt &stmt) override;
+
+  void visit (HIR::ExprStmt &stmt) override;
+
+protected: // Unused
+  // Only executable code of a single function/method is translated.
+  // All other items are ignored.
+  void visit (HIR::EnumItemTuple &tuple) override {}
+  void visit (HIR::EnumItemStruct &a_struct) override {}
+  void visit (HIR::EnumItem &item) override {}
+  void visit (HIR::TupleStruct &tuple_struct) override {}
+  void visit (HIR::EnumItemDiscriminant &discriminant) override {}
+  void visit (HIR::TypePathSegmentFunction &segment) override {}
+  void visit (HIR::TypePath &path) override {}
+  void visit (HIR::QualifiedPathInType &path) override {}
+  void visit (HIR::Module &module) override {}
+  void visit (HIR::ExternCrate &crate) override {}
+  void visit (HIR::UseDeclaration &use_decl) override {}
+  void visit (HIR::Function &function) override {}
+  void visit (HIR::TypeAlias &type_alias) override {}
+  void visit (HIR::StructStruct &struct_item) override {}
+  void visit (HIR::Enum &enum_item) override {}
+  void visit (HIR::Union &union_item) override {}
+  void visit (HIR::ConstantItem &const_item) override {}
+  void visit (HIR::StaticItem &static_item) override {}
+  void visit (HIR::Trait &trait) override {}
+  void visit (HIR::ImplBlock &impl) override {}
+  void visit (HIR::ExternBlock &block) override {}
+  void visit (HIR::EmptyStmt &stmt) override {}
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_EXPR_H
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
new file mode 100644 (file)
index 0000000..48116d8
--- /dev/null
@@ -0,0 +1,416 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_INTERNAL_H
+#define RUST_BIR_BUILDER_INTERNAL_H
+
+#include "rust-bir-place.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-item.h"
+#include "rust-hir-type-check.h"
+#include "rust-hir-visitor.h"
+#include "rust-name-resolver.h"
+#include "rust-bir.h"
+
+namespace Rust {
+
+namespace BIR {
+
+class LifetimeResolver
+{
+  using Index = uint32_t;
+  using Value = std::string;
+
+  Index next_index = FIRST_NORMAL_LIFETIME_ID;
+  std::unordered_map<Value, Index> value_to_index;
+
+public:
+  Index intern (const Value &value)
+  {
+    auto found = value_to_index.find (value);
+    if (found != value_to_index.end ())
+      {
+       return found->second;
+      }
+    value_to_index.emplace (value, next_index);
+    return next_index++;
+  }
+  Index get_anonymous () { return next_index++; }
+};
+
+struct BuilderContext
+{
+  struct LabelledBlockCtx
+  {
+    NodeId label; // UNKNOWN_NODEID if no label
+    PlaceId label_var;
+    BasicBlockId break_bb;
+    BasicBlockId continue_bb; // Only valid for loops
+  };
+
+  // Context
+  Resolver::TypeCheckContext &tyctx;
+  Resolver::Resolver &resolver;
+
+  std::vector<BasicBlock> basic_blocks;
+  size_t current_bb = 0;
+
+  /**
+   * Allocation and lookup of places (variables, temporaries, paths, and
+   * constants)
+   */
+  PlaceDB place_db;
+  LifetimeResolver lifetime_interner;
+  std::vector<PlaceId> arguments;
+  /**
+   * Since labels can be used to return values, we need to reserve a place for
+   * them. This map associates labels with their respective places.
+   */
+  std::unordered_map<NodeId, PlaceId> label_place_map;
+
+  std::vector<LabelledBlockCtx> loop_stack;
+
+public:
+  BuilderContext ()
+    : tyctx (*Resolver::TypeCheckContext::get ()),
+      resolver (*Resolver::Resolver::get ())
+  {
+    basic_blocks.emplace_back (); // StartBB
+  }
+
+  BasicBlock &get_current_bb () { return basic_blocks[current_bb]; }
+
+  Lifetime lookup_lifetime (const tl::optional<HIR::Lifetime> &lifetime)
+  {
+    if (!lifetime.has_value ())
+      return {lifetime_interner.get_anonymous ()};
+    switch (lifetime->get_lifetime_type ())
+      {
+       case AST::Lifetime::NAMED: {
+         return {lifetime_interner.intern (lifetime->get_name ())};
+       }
+       case AST::Lifetime::STATIC: {
+         return STATIC_LIFETIME;
+       }
+       case AST::Lifetime::WILDCARD: {
+         rust_sorry_at (lifetime->get_locus (),
+                        "lifetime elision is not yet implemented");
+         return NO_LIFETIME;
+       }
+      }
+    rust_unreachable ();
+  };
+};
+
+// Common infrastructure for building BIR from HIR.
+class AbstractBuilder
+{
+protected:
+  BuilderContext &ctx;
+
+  // This emulates the return value of the visitor, to be able to use the
+  // current visitor infrastructure, where the return value is forced to be
+  // void.
+  PlaceId translated = INVALID_PLACE;
+
+protected:
+  explicit AbstractBuilder (BuilderContext &ctx) : ctx (ctx) {}
+
+  WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Expr &expr)
+  {
+    return expr.get_mappings ().get_nodeid ();
+  }
+
+  WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Pattern &pattern)
+  {
+    return pattern.get_mappings ().get_nodeid ();
+  }
+
+  template <typename T>
+  WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (T &pattern) const
+  {
+    return lookup_type (pattern.get_mappings ().get_hirid ());
+  }
+
+  WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (HirId hirid) const
+  {
+    TyTy::BaseType *type = nullptr;
+    bool ok = ctx.tyctx.lookup_type (hirid, &type);
+    rust_assert (ok);
+    rust_assert (type != nullptr);
+    return type;
+  }
+
+  PlaceId declare_variable (const Analysis::NodeMapping &node)
+  {
+    const NodeId nodeid = node.get_nodeid ();
+    const HirId hirid = node.get_hirid ();
+
+    // In debug mode check that the variable is not already declared.
+    rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
+
+    return ctx.place_db.add_variable (nodeid, lookup_type (hirid));
+  }
+
+  PlaceId declare_variable (const Analysis::NodeMapping &node,
+                           TyTy::BaseType *type)
+  {
+    const NodeId nodeid = node.get_nodeid ();
+
+    // In debug mode check that the variable is not already declared.
+    rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
+
+    return ctx.place_db.add_variable (nodeid, type);
+  }
+
+  void push_assignment (PlaceId lhs, AbstractExpr *rhs)
+  {
+    ctx.get_current_bb ().statements.emplace_back (lhs, rhs);
+    translated = lhs;
+  }
+
+  void push_assignment (PlaceId lhs, PlaceId rhs)
+  {
+    push_assignment (lhs, new Assignment (rhs));
+  }
+
+  void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty)
+  {
+    PlaceId tmp = ctx.place_db.add_temporary (tyty);
+    push_assignment (tmp, rhs);
+  }
+
+  void push_switch (PlaceId switch_val)
+  {
+    ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH,
+                                                  switch_val);
+  }
+
+  void push_storage_dead (PlaceId place)
+  {
+    ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_DEAD,
+                                                  place);
+  }
+
+  void push_storage_live (PlaceId place)
+  {
+    ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_LIVE,
+                                                  place);
+  }
+
+  BasicBlockId new_bb ()
+  {
+    ctx.basic_blocks.emplace_back ();
+    return ctx.basic_blocks.size () - 1;
+  }
+
+  BasicBlockId start_new_subsequent_bb ()
+  {
+    BasicBlockId bb = new_bb ();
+    ctx.get_current_bb ().successors.emplace_back (bb);
+    ctx.current_bb = bb;
+    return bb;
+  }
+
+  void add_jump (BasicBlockId from, BasicBlockId to)
+  {
+    ctx.basic_blocks[from].successors.emplace_back (to);
+  }
+
+  void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); }
+
+protected:
+  template <typename T> bool resolve_label (T &label, NodeId &resolved_label)
+  {
+    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;
+  }
+
+  template <typename T>
+  bool resolve_variable (T &variable, PlaceId &resolved_variable)
+  {
+    NodeId variable_id;
+    if (!ctx.resolver.lookup_resolved_name (
+         variable.get_mappings ().get_nodeid (), &variable_id))
+      {
+       // TODO: should this be assert? (should be caught by typecheck)
+       rust_error_at (variable.get_locus (), "unresolved variable");
+       return false;
+      }
+    resolved_variable = ctx.place_db.lookup_variable (variable_id);
+    return true;
+  }
+
+  bool find_block_ctx (NodeId label, BuilderContext::LabelledBlockCtx &block)
+  {
+    if (ctx.loop_stack.empty ())
+      return false;
+    if (label == UNKNOWN_NODEID)
+      {
+       block = ctx.loop_stack.back ();
+       return true;
+      }
+    auto found
+      = std::find_if (ctx.loop_stack.rbegin (), ctx.loop_stack.rend (),
+                     [&label] (const BuilderContext::LabelledBlockCtx &block) {
+                       return block.label == label;
+                     });
+    if (found == ctx.loop_stack.rend ())
+      return false;
+    block = *found;
+    return true;
+  }
+
+  /**
+   * Performs implicit coercions on the `translated` place defined for a
+   * coercion site.
+   *
+   * Reference: https://doc.rust-lang.org/reference/type-coercions.html
+   *
+   * The only coercion relevant to BIR is the autoderef. All other coercions
+   * will be taken in account because the type is extracted from each node and
+   * not derived from operations in HIR/BIR. The borrowck does not care about
+   * type transitions. Lifetimes are not coerced, rather new are created with
+   * defined bounds to the original ones.
+   */
+  void coercion_site (PlaceId &place, TyTy::BaseType *expected_ty)
+  {
+    auto count_ref_levels = [] (TyTy::BaseType *ty) {
+      size_t count = 0;
+      while (auto r = ty->try_as<TyTy::ReferenceType> ())
+       {
+         ty = r->get_base ();
+         count++;
+       }
+      return count;
+    };
+
+    auto actual_ty = ctx.place_db[place].tyty;
+
+    auto deref_count
+      = count_ref_levels (actual_ty) - count_ref_levels (expected_ty);
+
+    for (size_t i = 0; i < deref_count; ++i)
+      {
+       actual_ty = actual_ty->as<TyTy::ReferenceType> ()->get_base ();
+       place
+         = ctx.place_db.lookup_or_add_path (Place::DEREF, actual_ty, place);
+      }
+  }
+
+  /** 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;
+    while (auto ref_ty = ty->try_as<TyTy::ReferenceType> ())
+      {
+       ty = ref_ty->get_base ();
+       place = ctx.place_db.lookup_or_add_path (Place::DEREF, ty, place);
+      }
+    return ty;
+  }
+
+  /** For operator  */
+  void autoref ()
+  {
+    if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF)
+      {
+       auto ty = ctx.place_db[translated].tyty;
+       push_tmp_assignment (
+         new BorrowExpr (translated),
+         new TyTy::ReferenceType (ty->get_ref (), TyTy::TyVar (ty->get_ref ()),
+                                  Mutability::Imm));
+      }
+  }
+};
+
+class AbstractExprBuilder : public AbstractBuilder,
+                           public HIR::HIRExpressionVisitor
+{
+protected:
+  // Exactly one of this and `translated` is used by each visitor.
+  AbstractExpr *expr_return_expr = nullptr;
+
+protected:
+  explicit AbstractExprBuilder (BuilderContext &ctx) : AbstractBuilder (ctx) {}
+
+  PlaceId visit_expr (HIR::Expr &expr)
+  {
+    // Reset return places.
+    translated = INVALID_PLACE;
+    expr_return_expr = nullptr;
+    expr.accept_vis (*this);
+    if (translated != INVALID_PLACE)
+      {
+       auto result = translated;
+       translated = INVALID_PLACE;
+       return result;
+      }
+    else if (expr_return_expr != nullptr)
+      {
+       // Only allocate temporary, if needed.
+       push_tmp_assignment (expr_return_expr, lookup_type (expr));
+       expr_return_expr = nullptr;
+       return translated;
+      }
+    else
+      {
+       return ctx.place_db.get_constant (lookup_type (expr));
+      }
+  }
+
+  void return_expr (AbstractExpr *expr, TyTy::BaseType *ty,
+                   bool can_panic = false)
+  {
+    rust_assert (expr_return_expr == nullptr);
+    if (can_panic)
+      {
+       push_tmp_assignment (expr, ty);
+       // TODO, cleanup?
+       start_new_subsequent_bb ();
+      }
+    else
+      {
+       translated = INVALID_PLACE;
+       expr_return_expr = expr;
+      }
+  }
+
+  void return_place (PlaceId place)
+  {
+    expr_return_expr = nullptr;
+    translated = place;
+  }
+
+  void return_unit (HIR::Expr &expr)
+  {
+    expr_return_expr = nullptr;
+    translated = ctx.place_db.get_constant (lookup_type (expr));
+  }
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_INTERNAL_H
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
new file mode 100644 (file)
index 0000000..4ec87d9
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_LAZYBOOLEXPR_H
+#define RUST_BIR_BUILDER_LAZYBOOLEXPR_H
+
+#include "rust-bir-builder-internal.h"
+#include "rust-bir-builder-expr-stmt.h"
+#include "rust-hir-expr.h"
+
+namespace Rust {
+namespace BIR {
+
+/**
+ * Special builder is needed to store short-circuiting context for directly
+ * nested lazy boolean expressions.
+ */
+class LazyBooleanExprBuilder : public AbstractBuilder,
+                              public HIR::HIRExpressionVisitor
+{
+  BasicBlockId short_circuit_bb;
+
+public:
+  explicit LazyBooleanExprBuilder (BuilderContext &ctx)
+    : AbstractBuilder (ctx), short_circuit_bb (0)
+  {}
+
+  PlaceId build (HIR::LazyBooleanExpr &expr)
+  {
+    PlaceId return_place = ctx.place_db.add_temporary (lookup_type (expr));
+
+    short_circuit_bb = new_bb ();
+    visit (expr);
+    push_assignment (return_place, translated);
+    auto final_bb = new_bb ();
+    add_jump_to (final_bb);
+
+    ctx.current_bb = short_circuit_bb;
+    translated = ctx.place_db.get_constant (lookup_type (expr));
+    push_assignment (return_place, translated);
+    add_jump_to (final_bb);
+
+    ctx.current_bb = final_bb;
+    return return_place;
+  }
+
+protected:
+  void visit (HIR::LazyBooleanExpr &expr) override
+  {
+    expr.get_lhs ()->accept_vis (*this);
+    push_switch (translated);
+    add_jump_to (short_circuit_bb);
+
+    start_new_subsequent_bb ();
+    expr.get_rhs ()->accept_vis (*this);
+  }
+  void visit (HIR::GroupedExpr &expr) override
+  {
+    expr.get_expr_in_parens ()->accept_vis (*this);
+  }
+
+protected:
+public:
+  void visit (HIR::QualifiedPathInExpression &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::PathInExpression &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ClosureExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::StructExprStructFields &fields) override
+  {
+    ExprStmtBuilder (ctx).build (fields);
+  }
+  void visit (HIR::StructExprStruct &a_struct) override
+  {
+    ExprStmtBuilder (ctx).build (a_struct);
+  }
+  void visit (HIR::LiteralExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::BorrowExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::DereferenceExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ErrorPropagationExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::NegationExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ArithmeticOrLogicalExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ComparisonExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::TypeCastExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::AssignmentExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::CompoundAssignmentExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ArrayExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::ArrayIndexExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::TupleExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::TupleIndexExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::CallExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::MethodCallExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::FieldAccessExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::BlockExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::UnsafeBlockExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::LoopExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::WhileLoopExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::WhileLetLoopExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::IfExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::IfExprConseqElse &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::IfLetExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::IfLetExprConseqElse &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::MatchExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::AwaitExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+  void visit (HIR::AsyncBlockExpr &expr) override
+  {
+    translated = ExprStmtBuilder (ctx).build (expr);
+  }
+
+protected: // Illegal at this position.
+  void visit (HIR::StructExprFieldIdentifier &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructExprFieldIdentifierValue &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructExprFieldIndexValue &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BreakExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromToExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeToExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFullExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); }
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_LAZYBOOLEXPR_H
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h
new file mode 100644 (file)
index 0000000..0b4c83e
--- /dev/null
@@ -0,0 +1,290 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_PATTERN_H
+#define RUST_BIR_BUILDER_PATTERN_H
+
+#include "rust-bir-builder-internal.h"
+
+namespace Rust {
+namespace BIR {
+// Compiles binding of values into newly created variables.
+// Used in let, match arm, and function parameter patterns.
+class PatternBindingBuilder : protected AbstractBuilder,
+                             public HIR::HIRPatternVisitor
+{
+  PlaceId init;
+  // This is where lifetime annotations are stored.
+  tl::optional<HIR::Type *> type;
+
+  // Emulates recursive stack saving and restoring inside a visitor.
+  class SavedState
+  {
+    PatternBindingBuilder *builder;
+
+  public:
+    const PlaceId init;
+    const tl::optional<HIR::Type *> type;
+
+  public:
+    explicit SavedState (PatternBindingBuilder *builder)
+      : builder (builder), init (builder->init), type (builder->type)
+    {}
+
+    ~SavedState ()
+    {
+      builder->init = init;
+      builder->type = type;
+    }
+  };
+
+public:
+  PatternBindingBuilder (BuilderContext &ctx, PlaceId init, HIR::Type *type)
+    : AbstractBuilder (ctx), init (init),
+      type (type ? tl::optional<HIR::Type *> (type) : tl::nullopt)
+  {}
+
+  void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); }
+
+  void visit_identifier (const Analysis::NodeMapping &node, bool is_ref)
+  {
+    translated = declare_variable (node);
+    if (is_ref)
+      {
+       push_assignment (translated, new BorrowExpr (init));
+      }
+    else
+      {
+       push_assignment (translated, init);
+      }
+    auto &init_place = ctx.place_db[init];
+    auto &translated_place = ctx.place_db[translated];
+    if (init_place.tyty->get_kind () == TyTy::REF)
+      {
+       init_place.lifetime = ctx.lookup_lifetime (type.map ([] (HIR::Type *t) {
+         return static_cast<HIR::ReferenceType *> (t)->get_lifetime ();
+       }));
+       translated_place.lifetime = init_place.lifetime;
+      }
+  }
+
+  void visit (HIR::IdentifierPattern &pattern) override
+  {
+    // Top-level identifiers are resolved directly to avoid useless temporary
+    // (for cleaner BIR).
+    visit_identifier (pattern.get_mappings (), pattern.get_is_ref ());
+  }
+  void visit (HIR::ReferencePattern &pattern) override
+  {
+    SavedState saved (this);
+
+    auto ref_type = type.map (
+      [] (HIR::Type *t) { return static_cast<HIR::ReferenceType *> (t); });
+
+    type = ref_type.map (
+      [] (HIR::ReferenceType *r) { return r->get_base_type ().get (); });
+    init = ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern),
+                                           saved.init);
+    ctx.place_db[init].lifetime
+      = ctx.lookup_lifetime (ref_type.map (&HIR::ReferenceType::get_lifetime));
+    pattern.get_referenced_pattern ()->accept_vis (*this);
+  }
+  void visit (HIR::SlicePattern &pattern) override
+  {
+    SavedState saved (this);
+
+    type = type.map ([] (HIR::Type *t) {
+      return static_cast<HIR::SliceType *> (t)->get_element_type ().get ();
+    });
+    // All indexes are supposed to point to the same place for borrow-checking.
+    init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern),
+                                           saved.init);
+    for (auto &item : pattern.get_items ())
+      {
+       item->accept_vis (*this);
+      }
+  }
+  void visit (HIR::AltPattern &pattern) override
+  {
+    rust_sorry_at (pattern.get_locus (),
+                  "borrow-checking of alt patterns is not yet implemented");
+  }
+  void visit (HIR::StructPattern &pattern) override
+  {
+    SavedState saved (this);
+
+    auto tyty = ctx.place_db[init].tyty;
+    rust_assert (tyty->get_kind () == TyTy::ADT);
+    auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
+    rust_assert (adt_ty->is_struct_struct ());
+    auto struct_ty = adt_ty->get_variants ().at (0);
+
+    auto struct_type = type.map ([] (HIR::Type *t) {
+      return static_cast<HIR::TypePath *> (t)->get_final_segment ().get ();
+    });
+    for (auto &field :
+        pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
+      {
+       switch (field->get_item_type ())
+         {
+           case HIR::StructPatternField::TUPLE_PAT: {
+             auto tuple
+               = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ());
+             init = ctx.place_db.lookup_or_add_path (
+               Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()),
+               saved.init, tuple->get_index ());
+             tuple->get_tuple_pattern ()->accept_vis (*this);
+             break;
+           }
+           case HIR::StructPatternField::IDENT_PAT: {
+             auto ident_field
+               = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ());
+             TyTy::StructFieldType *field_ty = nullptr;
+             size_t field_index = 0;
+             auto ok = struct_ty->lookup_field (
+               ident_field->get_identifier ().as_string (), &field_ty,
+               &field_index);
+             rust_assert (ok);
+             init
+               = ctx.place_db.lookup_or_add_path (Place::FIELD,
+                                                  field_ty->get_field_type (),
+                                                  saved.init, field_index);
+             ident_field->get_pattern ()->accept_vis (*this);
+             break;
+           }
+           case HIR::StructPatternField::IDENT: {
+             auto ident_field
+               = static_cast<HIR::StructPatternFieldIdent *> (field.get ());
+             TyTy::StructFieldType *field_ty = nullptr;
+             size_t field_index = 0;
+             auto ok = struct_ty->lookup_field (
+               ident_field->get_identifier ().as_string (), &field_ty,
+               &field_index);
+             rust_assert (ok);
+             init
+               = ctx.place_db.lookup_or_add_path (Place::FIELD,
+                                                  field_ty->get_field_type (),
+                                                  saved.init, field_index);
+             visit_identifier (ident_field->get_mappings (),
+                               ident_field->get_has_ref ());
+             break;
+           }
+         }
+      }
+  }
+  void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields,
+                          SavedState &saved, size_t &index)
+  {
+    for (auto &item : fields)
+      {
+       type = saved.type.map ([&] (HIR::Type *t) {
+         return static_cast<HIR::TupleType *> (t)
+           ->get_elems ()
+           .at (index)
+           .get ();
+       });
+       init
+         = ctx.place_db.lookup_or_add_path (Place::FIELD, lookup_type (*item),
+                                            saved.init, index);
+       item->accept_vis (*this);
+       index++;
+      }
+  }
+  void visit (HIR::TuplePattern &pattern) override
+  {
+    SavedState saved (this);
+
+    size_t index = 0;
+    switch (pattern.get_items ()->get_item_type ())
+      {
+       case HIR::TuplePatternItems::MULTIPLE: {
+         auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
+           *pattern.get_items ());
+         visit_tuple_fields (items.get_patterns (), saved, index);
+         break;
+       }
+       case HIR::TuplePatternItems::RANGED: {
+         auto &items = static_cast<HIR::TuplePatternItemsRanged &> (
+           *pattern.get_items ());
+
+         auto tyty = ctx.place_db[init].tyty;
+         rust_assert (tyty->get_kind () == TyTy::TUPLE);
+
+         auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields ()
+                        - items.get_lower_patterns ().size ()
+                        - items.get_upper_patterns ().size ();
+
+         visit_tuple_fields (items.get_lower_patterns (), saved, index);
+         index += skipped;
+         visit_tuple_fields (items.get_upper_patterns (), saved, index);
+         break;
+       }
+      }
+    init = saved.init;
+  }
+  void visit (HIR::TupleStructPattern &pattern) override
+  {
+    SavedState saved (this);
+
+    size_t index = 0;
+    switch (pattern.get_items ()->get_item_type ())
+      {
+       case HIR::TupleStructItems::RANGE: {
+         auto &items
+           = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ());
+
+         auto tyty = ctx.place_db[init].tyty;
+         rust_assert (tyty->get_kind () == TyTy::ADT);
+         auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
+         rust_assert (adt_ty->is_tuple_struct ());
+
+         auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size ()
+                        - items.get_lower_patterns ().size ()
+                        - items.get_upper_patterns ().size ();
+
+         visit_tuple_fields (items.get_lower_patterns (), saved, index);
+         index += skipped;
+         visit_tuple_fields (items.get_upper_patterns (), saved, index);
+         break;
+       }
+       case HIR::TupleStructItems::NO_RANGE: {
+         auto &items = static_cast<HIR::TupleStructItemsNoRange &> (
+           *pattern.get_items ());
+         visit_tuple_fields (items.get_patterns (), saved, index);
+         break;
+       }
+      }
+  }
+  void visit (HIR::WildcardPattern &pattern) override {}
+
+  // Unused for binding.
+  void visit (HIR::LiteralPattern &pattern) override {}
+  void visit (HIR::PathInExpression &expression) override {}
+  void visit (HIR::QualifiedPathInExpression &expression) override {}
+  void visit (HIR::RangePattern &pattern) override {}
+
+private:
+  template <typename T> tl::optional<T> *get_type ()
+  {
+    return static_cast<T *> (type);
+  }
+};
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_PATTERN_H
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
new file mode 100644 (file)
index 0000000..fa2f596
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_STRUCT_H
+#define RUST_BIR_BUILDER_STRUCT_H
+
+#include "rust-bir-builder-internal.h"
+#include "rust-bir-builder-expr-stmt.h"
+
+namespace Rust {
+namespace BIR {
+
+// Separated because it needs the struct type as a context.
+class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor
+{
+  TyTy::VariantDef *struct_ty;
+  std::vector<PlaceId> init_values;
+
+public:
+  StructBuilder (BuilderContext &ctx, TyTy::VariantDef *struct_ty)
+    : AbstractBuilder (ctx), struct_ty (struct_ty)
+  {
+    init_values.reserve (struct_ty->get_fields ().size ());
+  }
+
+  std::vector<PlaceId> &&build (HIR::StructExprStructFields &struct_expr)
+  {
+    for (auto &field : struct_expr.get_fields ())
+      field->accept_vis (*this);
+    return std::move (init_values);
+  }
+
+  void visit (HIR::StructExprFieldIdentifier &field) override
+  {
+    resolve_variable (field, translated);
+    handle_named_field (field);
+  }
+  void visit (HIR::StructExprFieldIdentifierValue &field) override
+  {
+    translated = ExprStmtBuilder (ctx).build (*field.get_value ());
+    handle_named_field (field);
+  }
+  void visit (HIR::StructExprFieldIndexValue &field) override
+  {
+    translated = ExprStmtBuilder (ctx).build (*field.get_value ());
+    coercion_site (translated,
+                  struct_ty->get_field_at_index (field.get_tuple_index ())
+                    ->get_field_type ());
+    init_values.push_back (translated);
+  }
+
+private:
+  template <typename T> void handle_named_field (T &field)
+  {
+    size_t field_index;
+    TyTy::StructFieldType *field_type;
+    bool ok = struct_ty->lookup_field (field.get_field_name ().as_string (),
+                                      &field_type, &field_index);
+    rust_assert (ok);
+    rust_assert (translated != INVALID_PLACE);
+    coercion_site (translated, field_type->get_field_type ());
+    init_values.push_back (translated);
+  }
+
+protected:
+  void visit (HIR::Lifetime &lifetime) override { rust_unreachable (); }
+  void visit (HIR::LifetimeParam &lifetime_param) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::PathInExpression &path) override { rust_unreachable (); }
+  void visit (HIR::TypePathSegment &segment) override { rust_unreachable (); }
+  void visit (HIR::TypePathSegmentGeneric &segment) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TypePathSegmentFunction &segment) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TypePath &path) override { rust_unreachable (); }
+  void visit (HIR::QualifiedPathInExpression &path) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::QualifiedPathInType &path) override { rust_unreachable (); }
+  void visit (HIR::LiteralExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BorrowExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::DereferenceExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ErrorPropagationExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::NegationExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ArithmeticOrLogicalExpr &expr) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::ComparisonExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::LazyBooleanExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::TypeCastExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::AssignmentExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::CompoundAssignmentExpr &expr) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::GroupedExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ArrayElemsValues &elems) override { rust_unreachable (); }
+  void visit (HIR::ArrayElemsCopied &elems) override { rust_unreachable (); }
+  void visit (HIR::ArrayExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ArrayIndexExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::TupleExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::TupleIndexExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::StructExprStruct &expr) override { rust_unreachable (); }
+  void visit (HIR::StructExprStructFields &expr) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructExprStructBase &expr) override { rust_unreachable (); }
+  void visit (HIR::CallExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::MethodCallExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::FieldAccessExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BlockExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ClosureExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BreakExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromToExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeToExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFullExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::UnsafeBlockExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::LoopExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::WhileLoopExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::WhileLetLoopExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::IfExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::IfExprConseqElse &expr) override { rust_unreachable (); }
+  void visit (HIR::IfLetExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::IfLetExprConseqElse &expr) override { rust_unreachable (); }
+  void visit (HIR::MatchExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::TypeParam &param) override { rust_unreachable (); }
+  void visit (HIR::ConstGenericParam &param) override { rust_unreachable (); }
+  void visit (HIR::LifetimeWhereClauseItem &item) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TypeBoundWhereClauseItem &item) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::Module &module) override { rust_unreachable (); }
+  void visit (HIR::ExternCrate &crate) override { rust_unreachable (); }
+  void visit (HIR::UseTreeGlob &use_tree) override { rust_unreachable (); }
+  void visit (HIR::UseTreeList &use_tree) override { rust_unreachable (); }
+  void visit (HIR::UseTreeRebind &use_tree) override { rust_unreachable (); }
+  void visit (HIR::UseDeclaration &use_decl) override { rust_unreachable (); }
+  void visit (HIR::Function &function) override { rust_unreachable (); }
+  void visit (HIR::TypeAlias &type_alias) override { rust_unreachable (); }
+  void visit (HIR::StructStruct &struct_item) override { rust_unreachable (); }
+  void visit (HIR::TupleStruct &tuple_struct) override { rust_unreachable (); }
+  void visit (HIR::EnumItem &item) override { rust_unreachable (); }
+  void visit (HIR::EnumItemTuple &item) override { rust_unreachable (); }
+  void visit (HIR::EnumItemStruct &item) override { rust_unreachable (); }
+  void visit (HIR::EnumItemDiscriminant &item) override { rust_unreachable (); }
+  void visit (HIR::Enum &enum_item) override { rust_unreachable (); }
+  void visit (HIR::Union &union_item) override { rust_unreachable (); }
+  void visit (HIR::ConstantItem &const_item) override { rust_unreachable (); }
+  void visit (HIR::StaticItem &static_item) override { rust_unreachable (); }
+  void visit (HIR::TraitItemFunc &item) override { rust_unreachable (); }
+  void visit (HIR::TraitItemConst &item) override { rust_unreachable (); }
+  void visit (HIR::TraitItemType &item) override { rust_unreachable (); }
+  void visit (HIR::Trait &trait) override { rust_unreachable (); }
+  void visit (HIR::ImplBlock &impl) override { rust_unreachable (); }
+  void visit (HIR::ExternalStaticItem &item) override { rust_unreachable (); }
+  void visit (HIR::ExternalFunctionItem &item) override { rust_unreachable (); }
+  void visit (HIR::ExternBlock &block) override { rust_unreachable (); }
+  void visit (HIR::LiteralPattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::IdentifierPattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::WildcardPattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::RangePatternBoundLiteral &bound) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::RangePatternBoundPath &bound) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::RangePatternBoundQualPath &bound) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::RangePattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::ReferencePattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::StructPatternFieldTuplePat &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructPatternFieldIdentPat &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructPatternFieldIdent &field) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::StructPattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::TupleStructItemsNoRange &tuple_items) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TupleStructItemsRange &tuple_items) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TupleStructPattern &pattern) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TuplePatternItemsMultiple &tuple_items) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TuplePatternItemsRanged &tuple_items) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::AltPattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); }
+  void visit (HIR::LetStmt &stmt) override { rust_unreachable (); }
+  void visit (HIR::ExprStmt &stmt) override { rust_unreachable (); }
+  void visit (HIR::TraitBound &bound) override { rust_unreachable (); }
+  void visit (HIR::ImplTraitType &type) override { rust_unreachable (); }
+  void visit (HIR::TraitObjectType &type) override { rust_unreachable (); }
+  void visit (HIR::ParenthesisedType &type) override { rust_unreachable (); }
+  void visit (HIR::ImplTraitTypeOneBound &type) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::TupleType &type) override { rust_unreachable (); }
+  void visit (HIR::NeverType &type) override { rust_unreachable (); }
+  void visit (HIR::RawPointerType &type) override { rust_unreachable (); }
+  void visit (HIR::ReferenceType &type) override { rust_unreachable (); }
+  void visit (HIR::ArrayType &type) override { rust_unreachable (); }
+  void visit (HIR::SliceType &type) override { rust_unreachable (); }
+  void visit (HIR::InferredType &type) override { rust_unreachable (); }
+  void visit (HIR::BareFunctionType &type) override { rust_unreachable (); }
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_STRUCT_H
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h
new file mode 100644 (file)
index 0000000..322d00d
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_BUILDER_H
+#define RUST_BIR_BUILDER_H
+
+#include "rust-bir-builder-internal.h"
+#include "rust-hir-visitor.h"
+#include "rust-bir-builder-pattern.h"
+#include "rust-bir-builder-struct.h"
+#include "rust-bir-builder-expr-stmt.h"
+
+namespace Rust {
+namespace BIR {
+
+/** Top-level builder, which compiles a HIR function into a BIR function. */
+class Builder : public AbstractBuilder
+{
+public:
+  explicit Builder (BuilderContext &ctx) : AbstractBuilder (ctx) {}
+
+  Function build (HIR::Function &function)
+  {
+    PlaceId return_place
+      = ctx.place_db.add_temporary (lookup_type (*function.get_definition ()));
+    rust_assert (return_place == RETURN_VALUE_PLACE);
+
+    for (auto &param : function.get_function_params ())
+      {
+       handle_param (param);
+      }
+
+    handle_body (*function.get_definition ());
+
+    return Function{std::move (ctx.place_db), std::move (ctx.arguments),
+                   std::move (ctx.basic_blocks)};
+  };
+
+private:
+  void handle_param (HIR::FunctionParam &param)
+  {
+    auto &pattern = param.get_param_name ();
+    if (pattern->get_pattern_type () == HIR::Pattern::IDENTIFIER
+       && !static_cast<HIR::IdentifierPattern &> (*pattern).get_is_ref ())
+      {
+       // Avoid useless temporary variable for parameter.
+       translated = declare_variable (pattern->get_mappings ());
+       ctx.arguments.push_back (translated);
+      }
+    else
+      {
+       translated = ctx.place_db.add_temporary (lookup_type (*pattern));
+       ctx.arguments.push_back (translated);
+       PatternBindingBuilder (ctx, translated, param.get_type ().get ())
+         .go (*param.get_param_name ());
+      }
+  }
+
+  void handle_body (HIR::BlockExpr &body)
+  {
+    translated = ExprStmtBuilder (ctx).build (body);
+    if (body.has_expr ())
+      {
+       push_assignment (RETURN_VALUE_PLACE, translated);
+       ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN);
+      }
+  }
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_BUILDER_H
index 44d33c57838adb477e0525e9d329ea5452567991..4b9712538df33ce19f999804c2cddfb01790e01b 100644 (file)
@@ -18,8 +18,7 @@
 
 #include "rust-borrow-checker.h"
 #include "rust-function-collector.h"
-#include "rust-bir.h"
-#include "rust-bir-visitor.h"
+#include "rust-bir-builder.h"
 
 namespace Rust {
 namespace HIR {
@@ -30,8 +29,11 @@ BorrowChecker::go (HIR::Crate &crate)
   FunctionCollector collector;
   collector.go (crate);
 
-  for (auto func ATTRIBUTE_UNUSED : collector.get_functions ())
+  for (auto func : collector.get_functions ())
     {
+      BIR::BuilderContext ctx;
+      BIR::Builder builder (ctx);
+      builder.build (*func);
     }
 
   for (auto closure ATTRIBUTE_UNUSED : collector.get_closures ())
index 1d9529119474616fd941f1a02c118f330ada4df7..b1ecb8ca32e1d70e944952963c8c3069f1cb0512 100644 (file)
 // along with GCC; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-#include "rust-ast-dump.h"
-#include "rust-ast-lower.h"
+#include "rust-session-manager.h"
+#include "rust-diagnostics.h"
+#include "rust-unsafe-checker.h"
+#include "rust-lex.h"
+#include "rust-parse.h"
+#include "rust-macro-expand.h"
 #include "rust-ast-resolve.h"
-#include "rust-attribute-values.h"
-#include "rust-attributes.h"
-#include "rust-cfg-parser.h"
-#include "rust-cfg-strip.h"
-#include "rust-compile.h"
+#include "rust-ast-lower.h"
+#include "rust-hir-type-check.h"
+#include "rust-privacy-check.h"
 #include "rust-const-checker.h"
-#include "rust-diagnostics.h"
-#include "rust-early-name-resolver-2.0.h"
-#include "rust-early-name-resolver.h"
-#include "rust-expand-visitor.h"
-#include "rust-export-metadata.h"
-#include "rust-extern-crate.h"
 #include "rust-feature-gate.h"
-#include "rust-hir-dump.h"
-#include "rust-hir-type-check.h"
-#include "rust-imports.h"
-#include "rust-lex.h"
+#include "rust-compile.h"
+#include "rust-cfg-parser.h"
 #include "rust-lint-scan-deadcode.h"
 #include "rust-lint-unused-var.h"
-#include "rust-macro-expand.h"
-#include "rust-name-resolution-context.h"
-#include "rust-parse.h"
-#include "rust-privacy-check.h"
 #include "rust-readonly-check.h"
-#include "rust-session-manager.h"
+#include "rust-hir-dump.h"
+#include "rust-ast-dump.h"
+#include "rust-export-metadata.h"
+#include "rust-imports.h"
+#include "rust-extern-crate.h"
+#include "rust-attributes.h"
+#include "rust-early-name-resolver.h"
+#include "rust-name-resolution-context.h"
+#include "rust-early-name-resolver-2.0.h"
+#include "rust-cfg-strip.h"
+#include "rust-expand-visitor.h"
 #include "rust-unicode.h"
-#include "rust-unsafe-checker.h"
+#include "rust-attribute-values.h"
+#include "rust-borrow-checker.h"
 
 #include "input.h"
-#include "rust-borrow-checker.h"
-#include "rust-target.h"
 #include "selftest.h"
 #include "tm.h"
+#include "rust-target.h"
 
-extern bool saw_errors(void);
+extern bool
+saw_errors (void);
 
-extern Linemap *rust_get_linemap();
+extern Linemap *
+rust_get_linemap ();
 
 namespace Rust {
 
@@ -72,63 +74,75 @@ const char *kTargetOptionsDumpFile = "gccrs.target-options.dump";
 const std::string kDefaultCrateName = "rust_out";
 const size_t kMaxNameLength = 64;
 
-Session &Session::get_instance() {
+Session &
+Session::get_instance ()
+{
   static Session instance;
   return instance;
 }
 
-static std::string infer_crate_name(const std::string &filename) {
+static std::string
+infer_crate_name (const std::string &filename)
+{
   if (filename == "-")
     return kDefaultCrateName;
 
-  std::string crate = std::string(filename);
-  size_t path_sep = crate.find_last_of(file_separator);
+  std::string crate = std::string (filename);
+  size_t path_sep = crate.find_last_of (file_separator);
 
   // find the base filename
   if (path_sep != std::string::npos)
-    crate.erase(0, path_sep + 1);
+    crate.erase (0, path_sep + 1);
 
   // find the file stem name (remove file extension)
-  size_t ext_position = crate.find_last_of('.');
+  size_t ext_position = crate.find_last_of ('.');
   if (ext_position != std::string::npos)
-    crate.erase(ext_position);
+    crate.erase (ext_position);
 
   // Replace all the '-' symbols with '_' per Rust rules
-  for (auto &c : crate) {
-    if (c == '-')
-      c = '_';
-  }
+  for (auto &c : crate)
+    {
+      if (c == '-')
+       c = '_';
+    }
   return crate;
 }
 
 /* Validate the crate name using the ASCII rules */
 
-static bool validate_crate_name(const std::string &crate_name, Error &error) {
-  tl::optional<Utf8String> utf8_name_opt =
-      Utf8String::make_utf8_string(crate_name);
-  if (!utf8_name_opt.has_value()) {
-    error = Error(UNDEF_LOCATION, "crate name is not a valid UTF-8 string");
-    return false;
-  }
+static bool
+validate_crate_name (const std::string &crate_name, Error &error)
+{
+  tl::optional<Utf8String> utf8_name_opt
+    = Utf8String::make_utf8_string (crate_name);
+  if (!utf8_name_opt.has_value ())
+    {
+      error = Error (UNDEF_LOCATION, "crate name is not a valid UTF-8 string");
+      return false;
+    }
 
-  std::vector<Codepoint> uchars = utf8_name_opt->get_chars();
-  if (uchars.empty()) {
-    error = Error(UNDEF_LOCATION, "crate name cannot be empty");
-    return false;
-  }
-  if (uchars.size() > kMaxNameLength) {
-    error = Error(UNDEF_LOCATION, "crate name cannot exceed %lu characters",
-                  (unsigned long)kMaxNameLength);
-    return false;
-  }
-  for (Codepoint &c : uchars) {
-    if (!(is_alphabetic(c.value) || is_numeric(c.value) || c.value == '_')) {
-      error = Error(UNDEF_LOCATION,
-                    "invalid character %<%s%> in crate name: %<%s%>",
-                    c.as_string().c_str(), crate_name.c_str());
+  std::vector<Codepoint> uchars = utf8_name_opt->get_chars ();
+  if (uchars.empty ())
+    {
+      error = Error (UNDEF_LOCATION, "crate name cannot be empty");
+      return false;
+    }
+  if (uchars.size () > kMaxNameLength)
+    {
+      error = Error (UNDEF_LOCATION, "crate name cannot exceed %lu characters",
+                    (unsigned long) kMaxNameLength);
       return false;
     }
-  }
+  for (Codepoint &c : uchars)
+    {
+      if (!(is_alphabetic (c.value) || is_numeric (c.value) || c.value == '_'))
+       {
+         error = Error (UNDEF_LOCATION,
+                        "invalid character %<%s%> in crate name: %<%s%>",
+                        c.as_string ().c_str (), crate_name.c_str ());
+         return false;
+       }
+    }
   return true;
 }
 
@@ -139,333 +153,396 @@ Session::init ()
   targetrustm.rust_cpu_info ();
   targetrustm.rust_os_info ();
 
-  options.target_data.insert_key_value_pair("target_pointer_width",
-                                            std::to_string(POINTER_SIZE));
-  options.target_data.insert_key_value_pair(
-      "target_endian", BYTES_BIG_ENDIAN ? "big" : "little");
+  // target-independent values that should exist in all targets
+  options.target_data.insert_key_value_pair ("target_pointer_width",
+                                            std::to_string (POINTER_SIZE));
+  options.target_data.insert_key_value_pair ("target_endian", BYTES_BIG_ENDIAN
+                                                               ? "big"
+                                                               : "little");
 
   // setup singleton linemap
-  linemap = rust_get_linemap();
+  linemap = rust_get_linemap ();
 
   // setup backend to GCC GIMPLE
-  Backend::init();
+  Backend::init ();
 
   // setup mappings class
-  mappings = Analysis::Mappings::get();
+  mappings = Analysis::Mappings::get ();
 }
 
 /* Initialise default options. Actually called before handle_option, unlike init
  * itself. */
-void Session::init_options() {}
+void
+Session::init_options ()
+{}
 
 // Handle option selection.
-bool Session::handle_option(
-    enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED,
-    int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED,
-    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) {
+bool
+Session::handle_option (
+  enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED,
+  int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED,
+  const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
   // used to store whether results of various stuff are successful
   bool ret = true;
 
   // Handles options as listed in lang.opt.
-  switch (code) {
-  case OPT_I:
-  case OPT_L: {
-    // TODO: add search path
-    const std::string p = std::string(arg);
-    add_search_path(p);
-  } break;
-
-  case OPT_frust_extern_: {
-    std::string input(arg);
-    ret = handle_extern_option(input);
-  } break;
-  case OPT_frust_crate_:
-    // set the crate name
-    if (arg != nullptr) {
-      auto error = Error(UNDEF_LOCATION, std::string());
-      if ((ret = validate_crate_name(arg, error))) {
-        options.set_crate_name(arg);
-        options.crate_name_set_manually = true;
-      } else {
-        rust_assert(!error.message.empty());
-        error.emit();
+  switch (code)
+    {
+    case OPT_I:
+      case OPT_L: {
+       // TODO: add search path
+       const std::string p = std::string (arg);
+       add_search_path (p);
+      }
+      break;
+
+      case OPT_frust_extern_: {
+       std::string input (arg);
+       ret = handle_extern_option (input);
+      }
+      break;
+    case OPT_frust_crate_:
+      // set the crate name
+      if (arg != nullptr)
+       {
+         auto error = Error (UNDEF_LOCATION, std::string ());
+         if ((ret = validate_crate_name (arg, error)))
+           {
+             options.set_crate_name (arg);
+             options.crate_name_set_manually = true;
+           }
+         else
+           {
+             rust_assert (!error.message.empty ());
+             error.emit ();
+           }
+       }
+      else
+       ret = false;
+      break;
+
+    case OPT_frust_dump_:
+      // enable dump and return whether this was successful
+      if (arg != nullptr)
+       {
+         ret = enable_dump (std::string (arg));
+       }
+      else
+       {
+         ret = false;
+       }
+      break;
+
+    case OPT_frust_mangling_:
+      Compile::Mangler::set_mangling (flag_rust_mangling);
+      break;
+
+      case OPT_frust_cfg_: {
+       auto string_arg = std::string (arg);
+       ret = handle_cfg_option (string_arg);
+       break;
       }
-    } else
-      ret = false;
-    break;
-
-  case OPT_frust_dump_:
-    // enable dump and return whether this was successful
-    if (arg != nullptr) {
-      ret = enable_dump(std::string(arg));
-    } else {
-      ret = false;
+    case OPT_frust_crate_type_:
+      options.set_crate_type (flag_rust_crate_type);
+      break;
+    case OPT_frust_edition_:
+      options.set_edition (flag_rust_edition);
+      break;
+    case OPT_frust_compile_until_:
+      options.set_compile_step (flag_rust_compile_until);
+      break;
+    case OPT_frust_metadata_output_:
+      options.set_metadata_output (arg);
+      break;
+
+    default:
+      break;
     }
-    break;
-
-  case OPT_frust_mangling_:
-    Compile::Mangler::set_mangling(flag_rust_mangling);
-    break;
-
-  case OPT_frust_cfg_: {
-    auto string_arg = std::string(arg);
-    ret = handle_cfg_option(string_arg);
-    break;
-  }
-  case OPT_frust_crate_type_:
-    options.set_crate_type(flag_rust_crate_type);
-    break;
-  case OPT_frust_edition_:
-    options.set_edition(flag_rust_edition);
-    break;
-  case OPT_frust_compile_until_:
-    options.set_compile_step(flag_rust_compile_until);
-    break;
-  case OPT_frust_metadata_output_:
-    options.set_metadata_output(arg);
-    break;
-
-  default:
-    break;
-  }
 
   return ret;
 }
 
-bool Session::handle_extern_option(std::string &input) {
-  auto pos = input.find('=');
+bool
+Session::handle_extern_option (std::string &input)
+{
+  auto pos = input.find ('=');
   if (std::string::npos == pos)
     return false;
 
-  std::string libname = input.substr(0, pos);
-  std::string path = input.substr(pos + 1);
+  std::string libname = input.substr (0, pos);
+  std::string path = input.substr (pos + 1);
 
-  extern_crates.insert({libname, path});
+  extern_crates.insert ({libname, path});
   return true;
 }
 
-bool Session::handle_cfg_option(std::string &input) {
+bool
+Session::handle_cfg_option (std::string &input)
+{
   std::string key;
   std::string value;
 
   // Refactor this if needed
-  if (!parse_cfg_option(input, key, value)) {
-    rust_error_at(
-        UNDEF_LOCATION,
-        "invalid argument to %<-frust-cfg%>: Accepted formats are "
-        "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)");
-    return false;
-  }
+  if (!parse_cfg_option (input, key, value))
+    {
+      rust_error_at (
+       UNDEF_LOCATION,
+       "invalid argument to %<-frust-cfg%>: Accepted formats are "
+       "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)");
+      return false;
+    }
 
-  if (value.empty())
+  if (value.empty ())
     // rustc does not seem to error on dup key
-    options.target_data.insert_key(key);
+    options.target_data.insert_key (key);
   else
-    options.target_data.insert_key_value_pair(key, value);
+    options.target_data.insert_key_value_pair (key, value);
 
   return true;
 }
 
 /* Enables a certain dump depending on the name passed in. Returns true if
  * name is valid, false otherwise. */
-bool Session::enable_dump(std::string arg) {
-  if (arg.empty()) {
-    rust_error_at(
-        UNDEF_LOCATION,
-        "dump option was not given a name. choose %<lex%>, %<ast-pretty%>, "
-        "%<register_plugins%>, %<injection%>, "
-        "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
-        "%<hir-pretty%>, %<bir%> or %<all%>");
-    return false;
-  }
-
-  if (arg == "all") {
-    options.enable_all_dump_options();
-  } else if (arg == "lex") {
-    options.enable_dump_option(CompileOptions::LEXER_DUMP);
-  } else if (arg == "ast-pretty") {
-    options.enable_dump_option(CompileOptions::AST_DUMP_PRETTY);
-  } else if (arg == "register_plugins") {
-    options.enable_dump_option(CompileOptions::REGISTER_PLUGINS_DUMP);
-  } else if (arg == "injection") {
-    options.enable_dump_option(CompileOptions::INJECTION_DUMP);
-  } else if (arg == "expansion") {
-    options.enable_dump_option(CompileOptions::EXPANSION_DUMP);
-  } else if (arg == "resolution") {
-    options.enable_dump_option(CompileOptions::RESOLUTION_DUMP);
-  } else if (arg == "target_options") {
-    options.enable_dump_option(CompileOptions::TARGET_OPTION_DUMP);
-  } else if (arg == "hir") {
-    options.enable_dump_option(CompileOptions::HIR_DUMP);
-  } else if (arg == "hir-pretty") {
-    options.enable_dump_option(CompileOptions::HIR_DUMP_PRETTY);
-  } else if (arg == "bir") {
-    options.enable_dump_option(CompileOptions::BIR_DUMP);
-  } else {
-    rust_error_at(
-        UNDEF_LOCATION,
-        "dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, "
-        "%<register_plugins%>, %<injection%>, "
-        "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
-        "%<hir-pretty%>, or %<all%>",
-        arg.c_str());
-    return false;
-  }
+bool
+Session::enable_dump (std::string arg)
+{
+  if (arg.empty ())
+    {
+      rust_error_at (
+       UNDEF_LOCATION,
+       "dump option was not given a name. choose %<lex%>, %<ast-pretty%>, "
+       "%<register_plugins%>, %<injection%>, "
+       "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
+       "%<hir-pretty%>, %<bir%> or %<all%>");
+      return false;
+    }
+
+  if (arg == "all")
+    {
+      options.enable_all_dump_options ();
+    }
+  else if (arg == "lex")
+    {
+      options.enable_dump_option (CompileOptions::LEXER_DUMP);
+    }
+  else if (arg == "ast-pretty")
+    {
+      options.enable_dump_option (CompileOptions::AST_DUMP_PRETTY);
+    }
+  else if (arg == "register_plugins")
+    {
+      options.enable_dump_option (CompileOptions::REGISTER_PLUGINS_DUMP);
+    }
+  else if (arg == "injection")
+    {
+      options.enable_dump_option (CompileOptions::INJECTION_DUMP);
+    }
+  else if (arg == "expansion")
+    {
+      options.enable_dump_option (CompileOptions::EXPANSION_DUMP);
+    }
+  else if (arg == "resolution")
+    {
+      options.enable_dump_option (CompileOptions::RESOLUTION_DUMP);
+    }
+  else if (arg == "target_options")
+    {
+      options.enable_dump_option (CompileOptions::TARGET_OPTION_DUMP);
+    }
+  else if (arg == "hir")
+    {
+      options.enable_dump_option (CompileOptions::HIR_DUMP);
+    }
+  else if (arg == "hir-pretty")
+    {
+      options.enable_dump_option (CompileOptions::HIR_DUMP_PRETTY);
+    }
+  else if (arg == "bir")
+    {
+      options.enable_dump_option (CompileOptions::BIR_DUMP);
+    }
+  else
+    {
+      rust_error_at (
+       UNDEF_LOCATION,
+       "dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, "
+       "%<register_plugins%>, %<injection%>, "
+       "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
+       "%<hir-pretty%>, or %<all%>",
+       arg.c_str ());
+      return false;
+    }
   return true;
 }
 
 /* Actual main entry point for front-end. Called from langhook to parse files.
  */
-void Session::handle_input_files(int num_files, const char **files) {
+void
+Session::handle_input_files (int num_files, const char **files)
+{
   if (num_files != 1)
-    rust_fatal_error(UNDEF_LOCATION,
-                     "only one file may be specified on the command line");
+    rust_fatal_error (UNDEF_LOCATION,
+                     "only one file may be specified on the command line");
 
   const auto &file = files[0];
 
-  if (options.crate_name.empty()) {
-    auto filename = "-";
-    if (num_files > 0)
-      filename = files[0];
-
-    auto crate_name = infer_crate_name(filename);
-    rust_debug("inferred crate name: %s", crate_name.c_str());
-    // set the preliminary crate name here
-    // we will figure out the real crate name in `handle_crate_name`
-    options.set_crate_name(crate_name);
-  }
+  if (options.crate_name.empty ())
+    {
+      auto filename = "-";
+      if (num_files > 0)
+       filename = files[0];
+
+      auto crate_name = infer_crate_name (filename);
+      rust_debug ("inferred crate name: %s", crate_name.c_str ());
+      // set the preliminary crate name here
+      // we will figure out the real crate name in `handle_crate_name`
+      options.set_crate_name (crate_name);
+    }
 
-  CrateNum crate_num = mappings->get_next_crate_num(options.get_crate_name());
-  mappings->set_current_crate(crate_num);
+  CrateNum crate_num = mappings->get_next_crate_num (options.get_crate_name ());
+  mappings->set_current_crate (crate_num);
 
-  rust_debug("Attempting to parse file: %s", file);
-  compile_crate(file);
+  rust_debug ("Attempting to parse file: %s", file);
+  compile_crate (file);
 }
 
-void Session::handle_crate_name(const AST::Crate &parsed_crate) {
-  auto mappings = Analysis::Mappings::get();
+void
+Session::handle_crate_name (const AST::Crate &parsed_crate)
+{
+  auto mappings = Analysis::Mappings::get ();
   auto crate_name_changed = false;
-  auto error = Error(UNDEF_LOCATION, std::string());
-
-  for (const auto &attr : parsed_crate.inner_attrs) {
-    if (attr.get_path() != "crate_name")
-      continue;
-    if (!attr.has_attr_input()) {
-      rust_error_at(attr.get_locus(), "%<crate_name%> accepts one argument");
-      continue;
-    }
-
-    auto &literal = static_cast<AST::AttrInputLiteral &>(attr.get_attr_input());
-    const auto &msg_str = literal.get_literal().as_string();
-    if (!validate_crate_name(msg_str, error)) {
-      error.locus = attr.get_locus();
-      error.emit();
-      continue;
-    }
-
-    auto options = Session::get_instance().options;
-    if (options.crate_name_set_manually && (options.crate_name != msg_str)) {
-      rust_error_at(attr.get_locus(),
-                    "%<-frust-crate-name%> and %<#[crate_name]%> are "
-                    "required to match, but %qs does not match %qs",
-                    options.crate_name.c_str(), msg_str.c_str());
+  auto error = Error (UNDEF_LOCATION, std::string ());
+
+  for (const auto &attr : parsed_crate.inner_attrs)
+    {
+      if (attr.get_path () != "crate_name")
+       continue;
+      if (!attr.has_attr_input ())
+       {
+         rust_error_at (attr.get_locus (),
+                        "%<crate_name%> accepts one argument");
+         continue;
+       }
+
+      auto &literal
+       = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+      const auto &msg_str = literal.get_literal ().as_string ();
+      if (!validate_crate_name (msg_str, error))
+       {
+         error.locus = attr.get_locus ();
+         error.emit ();
+         continue;
+       }
+
+      auto options = Session::get_instance ().options;
+      if (options.crate_name_set_manually && (options.crate_name != msg_str))
+       {
+         rust_error_at (attr.get_locus (),
+                        "%<-frust-crate-name%> and %<#[crate_name]%> are "
+                        "required to match, but %qs does not match %qs",
+                        options.crate_name.c_str (), msg_str.c_str ());
+       }
+      crate_name_changed = true;
+      options.set_crate_name (msg_str);
+      mappings->set_crate_name (mappings->get_current_crate (), msg_str);
     }
-    crate_name_changed = true;
-    options.set_crate_name(msg_str);
-    mappings->set_crate_name(mappings->get_current_crate(), msg_str);
-  }
 
   options.crate_name_set_manually |= crate_name_changed;
-  if (!options.crate_name_set_manually &&
-      !validate_crate_name(options.crate_name, error)) {
-    error.emit();
-    rust_inform(linemap_position_for_column(line_table, 0),
-                "crate name inferred from this file");
-  }
+  if (!options.crate_name_set_manually
+      && !validate_crate_name (options.crate_name, error))
+    {
+      error.emit ();
+      rust_inform (linemap_position_for_column (line_table, 0),
+                  "crate name inferred from this file");
+    }
 }
 
 // Parses a single file with filename filename.
-void Session::compile_crate(const char *filename) {
-  if (!flag_rust_experimental &&
-      !std::getenv("GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE"))
-    rust_fatal_error(
-        UNDEF_LOCATION, "%s",
-        "gccrs is not yet able to compile Rust code "
-        "properly. Most of the errors produced will be gccrs' fault and not "
-        "the "
-        "crate you are trying to compile. Because of this, please reports "
-        "issues "
-        "to us directly instead of opening issues on said crate's "
-        "repository.\n\nOur github repository: "
-        "https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: "
-        "https://gcc.gnu.org/bugzilla/"
-        "buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n"
-        "If you understand this, and understand that the binaries produced "
-        "might "
-        "not behave accordingly, you may attempt to use gccrs in an "
-        "experimental "
-        "manner by passing the following flag:\n\n"
-        "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by "
-        "defining the following environment variable (any value will "
-        "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor "
-        "cargo-gccrs, this means passing\n\n"
-        "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-"
-        "use\"\n\nas an environment variable.");
-
-  RAIIFile file_wrap(filename);
-  if (!file_wrap.ok()) {
-    rust_error_at(UNDEF_LOCATION, "cannot open filename %s: %m", filename);
-    return;
-  }
+void
+Session::compile_crate (const char *filename)
+{
+  if (!flag_rust_experimental
+      && !std::getenv ("GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE"))
+    rust_fatal_error (
+      UNDEF_LOCATION, "%s",
+      "gccrs is not yet able to compile Rust code "
+      "properly. Most of the errors produced will be gccrs' fault and not the "
+      "crate you are trying to compile. Because of this, please reports issues "
+      "to us directly instead of opening issues on said crate's "
+      "repository.\n\nOur github repository: "
+      "https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: "
+      "https://gcc.gnu.org/bugzilla/"
+      "buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n"
+      "If you understand this, and understand that the binaries produced might "
+      "not behave accordingly, you may attempt to use gccrs in an experimental "
+      "manner by passing the following flag:\n\n"
+      "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by "
+      "defining the following environment variable (any value will "
+      "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor "
+      "cargo-gccrs, this means passing\n\n"
+      "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-"
+      "use\"\n\nas an environment variable.");
+
+  RAIIFile file_wrap (filename);
+  if (!file_wrap.ok ())
+    {
+      rust_error_at (UNDEF_LOCATION, "cannot open filename %s: %m", filename);
+      return;
+    }
 
-  auto last_step = options.get_compile_until();
+  auto last_step = options.get_compile_until ();
 
   // parse file here
   /* create lexer and parser - these are file-specific and so aren't instance
    * variables */
   tl::optional<std::ofstream &> dump_lex_opt = tl::nullopt;
   std::ofstream dump_lex_stream;
-  if (options.dump_option_enabled(CompileOptions::LEXER_DUMP)) {
-    dump_lex_stream.open(kLexDumpFile);
-    if (dump_lex_stream.fail())
-      rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
-                    kLexDumpFile);
-
-    dump_lex_opt = dump_lex_stream;
-  }
+  if (options.dump_option_enabled (CompileOptions::LEXER_DUMP))
+    {
+      dump_lex_stream.open (kLexDumpFile);
+      if (dump_lex_stream.fail ())
+       rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+                      kLexDumpFile);
+
+      dump_lex_opt = dump_lex_stream;
+    }
 
-  Lexer lex(filename, std::move(file_wrap), linemap, dump_lex_opt);
+  Lexer lex (filename, std::move (file_wrap), linemap, dump_lex_opt);
 
-  if (!lex.input_source_is_valid_utf8()) {
-    rust_error_at(UNKNOWN_LOCATION,
-                  "cannot read %s; stream did not contain valid UTF-8",
-                  filename);
-    return;
-  }
+  if (!lex.input_source_is_valid_utf8 ())
+    {
+      rust_error_at (UNKNOWN_LOCATION,
+                    "cannot read %s; stream did not contain valid UTF-8",
+                    filename);
+      return;
+    }
 
-  Parser<Lexer> parser(lex);
+  Parser<Lexer> parser (lex);
 
   // generate crate from parser
-  std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate();
+  std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate ();
 
   // handle crate name
-  handle_crate_name(*ast_crate.get());
+  handle_crate_name (*ast_crate.get ());
 
   // dump options except lexer dump
-  if (options.dump_option_enabled(CompileOptions::AST_DUMP_PRETTY)) {
-    dump_ast_pretty(*ast_crate.get());
-  }
-  if (options.dump_option_enabled(CompileOptions::TARGET_OPTION_DUMP)) {
-    options.target_data.dump_target_options();
-  }
-
-  if (saw_errors())
+  if (options.dump_option_enabled (CompileOptions::AST_DUMP_PRETTY))
+    {
+      dump_ast_pretty (*ast_crate.get ());
+    }
+  if (options.dump_option_enabled (CompileOptions::TARGET_OPTION_DUMP))
+    {
+      options.target_data.dump_target_options ();
+    }
+
+  if (saw_errors ())
     return;
 
   // setup the mappings for this AST
-  CrateNum current_crate = mappings->get_current_crate();
-  AST::Crate &parsed_crate =
-      mappings->insert_ast_crate(std::move(ast_crate), current_crate);
+  CrateNum current_crate = mappings->get_current_crate ();
+  AST::Crate &parsed_crate
+    = mappings->insert_ast_crate (std::move (ast_crate), current_crate);
 
   /* basic pipeline:
    *  - lex
@@ -481,7 +558,7 @@ void Session::compile_crate(const char *filename) {
    * maybe buffered lints)
    *  TODO not done */
 
-  rust_debug("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m");
+  rust_debug ("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m");
 
   // If -fsyntax-only was passed, we can just skip the remaining passes.
   // Parsing errors are already emitted in `parse_crate()`
@@ -489,107 +566,115 @@ void Session::compile_crate(const char *filename) {
     return;
 
   // register plugins pipeline stage
-  register_plugins(parsed_crate);
-  rust_debug("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m");
-  if (options.dump_option_enabled(CompileOptions::REGISTER_PLUGINS_DUMP)) {
-    // TODO: what do I dump here?
-  }
+  register_plugins (parsed_crate);
+  rust_debug ("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m");
+  if (options.dump_option_enabled (CompileOptions::REGISTER_PLUGINS_DUMP))
+    {
+      // TODO: what do I dump here?
+    }
 
   // injection pipeline stage
-  injection(parsed_crate);
-  rust_debug("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m");
-  if (options.dump_option_enabled(CompileOptions::INJECTION_DUMP)) {
-    // TODO: what do I dump here? injected crate names?
-  }
+  injection (parsed_crate);
+  rust_debug ("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m");
+  if (options.dump_option_enabled (CompileOptions::INJECTION_DUMP))
+    {
+      // TODO: what do I dump here? injected crate names?
+    }
 
   if (last_step == CompileOptions::CompileStep::AttributeCheck)
     return;
 
-  Analysis::AttributeChecker().go(parsed_crate);
+  Analysis::AttributeChecker ().go (parsed_crate);
 
   if (last_step == CompileOptions::CompileStep::Expansion)
     return;
 
   // expansion pipeline stage
-  expansion(parsed_crate);
-  rust_debug("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m");
-  if (options.dump_option_enabled(CompileOptions::EXPANSION_DUMP)) {
-    // dump AST with expanded stuff
-    rust_debug("BEGIN POST-EXPANSION AST DUMP");
-    dump_ast_pretty(parsed_crate, true);
-    rust_debug("END POST-EXPANSION AST DUMP");
-  }
+  expansion (parsed_crate);
+  rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m");
+  if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP))
+    {
+      // dump AST with expanded stuff
+      rust_debug ("BEGIN POST-EXPANSION AST DUMP");
+      dump_ast_pretty (parsed_crate, true);
+      rust_debug ("END POST-EXPANSION AST DUMP");
+    }
 
   // feature gating
-  FeatureGate().check(parsed_crate);
+  FeatureGate ().check (parsed_crate);
 
   if (last_step == CompileOptions::CompileStep::NameResolution)
     return;
 
   // resolution pipeline stage
-  Resolver::NameResolution::Resolve(parsed_crate);
+  Resolver::NameResolution::Resolve (parsed_crate);
 
-  if (options.dump_option_enabled(CompileOptions::RESOLUTION_DUMP)) {
-    // TODO: what do I dump here? resolved names? AST with resolved names?
-  }
+  if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP))
+    {
+      // TODO: what do I dump here? resolved names? AST with resolved names?
+    }
 
-  if (saw_errors())
+  if (saw_errors ())
     return;
 
   if (last_step == CompileOptions::CompileStep::Lowering)
     return;
 
   // lower AST to HIR
-  std::unique_ptr<HIR::Crate> lowered = HIR::ASTLowering::Resolve(parsed_crate);
-  if (saw_errors())
+  std::unique_ptr<HIR::Crate> lowered
+    = HIR::ASTLowering::Resolve (parsed_crate);
+  if (saw_errors ())
     return;
 
   // add the mappings to it
-  HIR::Crate &hir = mappings->insert_hir_crate(std::move(lowered));
-  if (options.dump_option_enabled(CompileOptions::HIR_DUMP)) {
-    dump_hir(hir);
-  }
-  if (options.dump_option_enabled(CompileOptions::HIR_DUMP_PRETTY)) {
-    dump_hir_pretty(hir);
-  }
+  HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered));
+  if (options.dump_option_enabled (CompileOptions::HIR_DUMP))
+    {
+      dump_hir (hir);
+    }
+  if (options.dump_option_enabled (CompileOptions::HIR_DUMP_PRETTY))
+    {
+      dump_hir_pretty (hir);
+    }
 
   if (last_step == CompileOptions::CompileStep::TypeCheck)
     return;
 
   // type resolve
-  Resolver::TypeResolution::Resolve(hir);
+  Resolver::TypeResolution::Resolve (hir);
 
-  if (saw_errors())
+  if (saw_errors ())
     return;
 
   if (last_step == CompileOptions::CompileStep::Privacy)
     return;
 
   // Various HIR error passes. The privacy pass happens before the unsafe checks
-  Privacy::Resolver::resolve(hir);
-  if (saw_errors())
+  Privacy::Resolver::resolve (hir);
+  if (saw_errors ())
     return;
 
   if (last_step == CompileOptions::CompileStep::Unsafety)
     return;
 
-  HIR::UnsafeChecker().go(hir);
+  HIR::UnsafeChecker ().go (hir);
 
   if (last_step == CompileOptions::CompileStep::Const)
     return;
 
-  HIR::ConstChecker().go(hir);
+  HIR::ConstChecker ().go (hir);
 
   if (last_step == CompileOptions::CompileStep::BorrowCheck)
     return;
 
-  if (flag_borrowcheck) {
-    const bool dump_bir =
-        options.dump_option_enabled(CompileOptions::DumpOption::BIR_DUMP);
-    HIR::BorrowChecker(dump_bir).go(hir);
-  }
+  if (flag_borrowcheck)
+    {
+      const bool dump_bir
+       = options.dump_option_enabled (CompileOptions::DumpOption::BIR_DUMP);
+      HIR::BorrowChecker (dump_bir).go (hir);
+    }
 
-  if (saw_errors())
+  if (saw_errors ())
     return;
 
   if (last_step == CompileOptions::CompileStep::Compilation)
@@ -597,49 +682,61 @@ void Session::compile_crate(const char *filename) {
 
   // do compile to gcc generic
   Compile::Context ctx;
-  Compile::CompileCrate::Compile(hir, &ctx);
+  Compile::CompileCrate::Compile (hir, &ctx);
 
   // we can't do static analysis if there are errors to worry about
-  if (!saw_errors()) {
-    // lints
-    Analysis::ScanDeadcode::Scan(hir);
-    Analysis::UnusedVariables::Lint(ctx);
-    Analysis::ReadonlyCheck::Lint(ctx);
-
-    // metadata
-    bool specified_emit_metadata =
-        flag_rust_embed_metadata || options.metadata_output_path_set();
-    if (!specified_emit_metadata) {
-      Metadata::PublicInterface::ExportTo(
-          hir, Metadata::PublicInterface::expected_metadata_filename());
-    } else {
-      if (flag_rust_embed_metadata)
-        Metadata::PublicInterface::Export(hir);
-      if (options.metadata_output_path_set())
-        Metadata::PublicInterface::ExportTo(hir, options.get_metadata_output());
+  if (!saw_errors ())
+    {
+      // lints
+      Analysis::ScanDeadcode::Scan (hir);
+      Analysis::UnusedVariables::Lint (ctx);
+      Analysis::ReadonlyCheck::Lint (ctx);
+
+      // metadata
+      bool specified_emit_metadata
+       = flag_rust_embed_metadata || options.metadata_output_path_set ();
+      if (!specified_emit_metadata)
+       {
+         Metadata::PublicInterface::ExportTo (
+           hir, Metadata::PublicInterface::expected_metadata_filename ());
+       }
+      else
+       {
+         if (flag_rust_embed_metadata)
+           Metadata::PublicInterface::Export (hir);
+         if (options.metadata_output_path_set ())
+           Metadata::PublicInterface::ExportTo (
+             hir, options.get_metadata_output ());
+       }
     }
-  }
 
   // pass to GCC middle-end
-  ctx.write_to_backend();
+  ctx.write_to_backend ();
 }
 
-void Session::register_plugins(AST::Crate &crate ATTRIBUTE_UNUSED) {
-  rust_debug("ran register_plugins (with no body)");
+void
+Session::register_plugins (AST::Crate &crate ATTRIBUTE_UNUSED)
+{
+  rust_debug ("ran register_plugins (with no body)");
 }
 
 // TODO: move somewhere else
-bool contains_name(const AST::AttrVec &attrs, std::string name) {
-  for (const auto &attr : attrs) {
-    if (attr.get_path() == name)
-      return true;
-  }
+bool
+contains_name (const AST::AttrVec &attrs, std::string name)
+{
+  for (const auto &attr : attrs)
+    {
+      if (attr.get_path () == name)
+       return true;
+    }
 
   return false;
 }
 
-void Session::injection(AST::Crate &crate) {
-  rust_debug("started injection");
+void
+Session::injection (AST::Crate &crate)
+{
+  rust_debug ("started injection");
 
   // lint checks in future maybe?
 
@@ -694,40 +791,47 @@ void Session::injection(AST::Crate &crate) {
 
   // crate injection
   std::vector<std::string> names;
-  if (contains_name(crate.inner_attrs, "no_core")) {
-    // no prelude
-    injected_crate_name = "";
-  } else if (contains_name(crate.inner_attrs, "no_std")) {
-    names.push_back("core");
-
-    if (!contains_name(crate.inner_attrs, "compiler_builtins")) {
-      names.push_back("compiler_builtins");
+  if (contains_name (crate.inner_attrs, "no_core"))
+    {
+      // no prelude
+      injected_crate_name = "";
     }
+  else if (contains_name (crate.inner_attrs, "no_std"))
+    {
+      names.push_back ("core");
+
+      if (!contains_name (crate.inner_attrs, "compiler_builtins"))
+       {
+         names.push_back ("compiler_builtins");
+       }
 
-    injected_crate_name = "core";
-  } else {
-    names.push_back("std");
+      injected_crate_name = "core";
+    }
+  else
+    {
+      names.push_back ("std");
 
-    injected_crate_name = "std";
-  }
+      injected_crate_name = "std";
+    }
 
   // reverse iterate through names to insert crate items in "forward" order at
   // beginning of crate
-  for (auto it = names.rbegin(); it != names.rend(); ++it) {
-    // create "macro use" attribute for use on extern crate item to enable
-    // loading macros from it
-    AST::Attribute attr(AST::SimplePath::from_str(Values::Attributes::MACRO_USE,
-                                                  UNDEF_LOCATION),
-                        nullptr);
-
-    // create "extern crate" item with the name
-    std::unique_ptr<AST::ExternCrate> extern_crate(
-        new AST::ExternCrate(*it, AST::Visibility::create_error(),
-                             {std::move(attr)}, UNKNOWN_LOCATION));
-
-    // insert at beginning
-    // crate.items.insert (crate.items.begin (), std::move (extern_crate));
-  }
+  for (auto it = names.rbegin (); it != names.rend (); ++it)
+    {
+      // create "macro use" attribute for use on extern crate item to enable
+      // loading macros from it
+      AST::Attribute attr (AST::SimplePath::from_str (
+                            Values::Attributes::MACRO_USE, UNDEF_LOCATION),
+                          nullptr);
+
+      // create "extern crate" item with the name
+      std::unique_ptr<AST::ExternCrate> extern_crate (
+       new AST::ExternCrate (*it, AST::Visibility::create_error (),
+                             {std::move (attr)}, UNKNOWN_LOCATION));
+
+      // insert at beginning
+      // crate.items.insert (crate.items.begin (), std::move (extern_crate));
+    }
 
   // create use tree path
   // prelude is injected_crate_name
@@ -761,11 +865,13 @@ void Session::injection(AST::Crate &crate) {
 
   // this crate type will have options affecting the metadata ouput
 
-  rust_debug("finished injection");
+  rust_debug ("finished injection");
 }
 
-void Session::expansion(AST::Crate &crate) {
-  rust_debug("started expansion");
+void
+Session::expansion (AST::Crate &crate)
+{
+  rust_debug ("started expansion");
 
   /* rustc has a modification to windows PATH temporarily here, which may end
    * up being required */
@@ -780,49 +886,53 @@ void Session::expansion(AST::Crate &crate) {
   // create extctxt? from parse session, cfg, and resolver?
   /* expand by calling cxtctxt object's monotonic_expander's expand_crate
    * method. */
-  MacroExpander expander(crate, cfg, *this);
+  MacroExpander expander (crate, cfg, *this);
   std::vector<Error> macro_errors;
 
-  while (!fixed_point_reached && iterations < cfg.recursion_limit) {
-    CfgStrip().go(crate);
-    // Errors might happen during cfg strip pass
-    if (saw_errors())
-      break;
-
-    auto ctx = Resolver2_0::NameResolutionContext();
-
-    if (flag_name_resolution_2_0) {
-      Resolver2_0::Early early(ctx);
-      early.go(crate);
-      macro_errors = early.get_macro_resolve_errors();
-    } else
-      Resolver::EarlyNameResolver().go(crate);
+  while (!fixed_point_reached && iterations < cfg.recursion_limit)
+    {
+      CfgStrip ().go (crate);
+      // Errors might happen during cfg strip pass
+      if (saw_errors ())
+       break;
+
+      auto ctx = Resolver2_0::NameResolutionContext ();
+
+      if (flag_name_resolution_2_0)
+       {
+         Resolver2_0::Early early (ctx);
+         early.go (crate);
+         macro_errors = early.get_macro_resolve_errors ();
+       }
+      else
+       Resolver::EarlyNameResolver ().go (crate);
 
-    ExpandVisitor(expander).go(crate);
+      ExpandVisitor (expander).go (crate);
 
-    fixed_point_reached = !expander.has_changed();
-    expander.reset_changed_state();
-    iterations++;
+      fixed_point_reached = !expander.has_changed ();
+      expander.reset_changed_state ();
+      iterations++;
 
-    if (saw_errors())
-      break;
-  }
+      if (saw_errors ())
+       break;
+    }
 
   // Fixed point reached: Emit unresolved macros error
   for (auto &error : macro_errors)
-    error.emit();
+    error.emit ();
 
-  if (iterations == cfg.recursion_limit) {
-    auto &last_invoc = expander.get_last_invocation();
-    auto &last_def = expander.get_last_definition();
+  if (iterations == cfg.recursion_limit)
+    {
+      auto &last_invoc = expander.get_last_invocation ();
+      auto &last_def = expander.get_last_definition ();
 
-    rust_assert(last_def.has_value() && last_invoc.has_value());
+      rust_assert (last_def.has_value () && last_invoc.has_value ());
 
-    rich_location range(line_table, last_invoc->get_locus());
-    range.add_range(last_def->get_locus());
+      rich_location range (line_table, last_invoc->get_locus ());
+      range.add_range (last_def->get_locus ());
 
-    rust_error_at(range, "reached recursion limit");
-  }
+      rust_error_at (range, "reached recursion limit");
+    }
 
   // error reporting - check unused macros, get missing fragment specifiers
 
@@ -832,254 +942,288 @@ void Session::expansion(AST::Crate &crate) {
 
   // maybe create macro crate if not rustdoc
 
-  rust_debug("finished expansion");
+  rust_debug ("finished expansion");
 }
 
-void Session::dump_ast_pretty(AST::Crate &crate, bool expanded) const {
+void
+Session::dump_ast_pretty (AST::Crate &crate, bool expanded) const
+{
   std::ofstream out;
   if (expanded)
-    out.open(kASTPrettyDumpFileExpanded);
+    out.open (kASTPrettyDumpFileExpanded);
   else
-    out.open(kASTPrettyDumpFile);
+    out.open (kASTPrettyDumpFile);
 
-  if (out.fail()) {
-    rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", kASTDumpFile);
-    return;
-  }
+  if (out.fail ())
+    {
+      rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+                    kASTDumpFile);
+      return;
+    }
 
-  AST::Dump(out).go(crate);
+  AST::Dump (out).go (crate);
 
-  out.close();
+  out.close ();
 }
 
-void Session::dump_hir(HIR::Crate &crate) const {
+void
+Session::dump_hir (HIR::Crate &crate) const
+{
   std::ofstream out;
-  out.open(kHIRDumpFile);
-  if (out.fail()) {
-    rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", kHIRDumpFile);
-    return;
-  }
+  out.open (kHIRDumpFile);
+  if (out.fail ())
+    {
+      rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+                    kHIRDumpFile);
+      return;
+    }
 
-  out << crate.as_string();
-  out.close();
+  out << crate.as_string ();
+  out.close ();
 }
 
-void Session::dump_hir_pretty(HIR::Crate &crate) const {
+void
+Session::dump_hir_pretty (HIR::Crate &crate) const
+{
   std::ofstream out;
-  out.open(kHIRPrettyDumpFile);
-  if (out.fail()) {
-    rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
-                  kHIRPrettyDumpFile);
-    return;
-  }
+  out.open (kHIRPrettyDumpFile);
+  if (out.fail ())
+    {
+      rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+                    kHIRPrettyDumpFile);
+      return;
+    }
 
-  HIR::Dump(out).go(crate);
-  out.close();
+  HIR::Dump (out).go (crate);
+  out.close ();
 }
 
 // imports
 
-NodeId Session::load_extern_crate(const std::string &crate_name,
-                                  location_t locus) {
+NodeId
+Session::load_extern_crate (const std::string &crate_name, location_t locus)
+{
   // has it already been loaded?
   CrateNum found_crate_num = UNKNOWN_CRATENUM;
-  bool found = mappings->lookup_crate_name(crate_name, found_crate_num);
-  if (found) {
-    NodeId resolved_node_id = UNKNOWN_NODEID;
-    bool resolved =
-        mappings->crate_num_to_nodeid(found_crate_num, resolved_node_id);
-    rust_assert(resolved);
-
-    return resolved_node_id;
-  }
+  bool found = mappings->lookup_crate_name (crate_name, found_crate_num);
+  if (found)
+    {
+      NodeId resolved_node_id = UNKNOWN_NODEID;
+      bool resolved
+       = mappings->crate_num_to_nodeid (found_crate_num, resolved_node_id);
+      rust_assert (resolved);
+
+      return resolved_node_id;
+    }
 
   std::string relative_import_path = "";
   std::string import_name = crate_name;
 
   // The path to the extern crate might have been specified by the user using
   // -frust-extern
-  auto cli_extern_crate = extern_crates.find(crate_name);
+  auto cli_extern_crate = extern_crates.find (crate_name);
 
   std::pair<std::unique_ptr<Import::Stream>, std::vector<ProcMacro::Procmacro>>
-      package_result;
-  if (cli_extern_crate != extern_crates.end()) {
-    auto path = cli_extern_crate->second;
-    package_result = Import::try_package_in_directory(path, locus);
-  } else {
-    package_result =
-        Import::open_package(import_name, locus, relative_import_path);
-  }
-
-  auto stream = std::move(package_result.first);
-  auto proc_macros = std::move(package_result.second);
-
-  if (stream == NULL          // No stream and
-      && proc_macros.empty()) // no proc macros
-  {
-    rust_error_at(locus, "failed to locate crate %<%s%>", import_name.c_str());
-    return UNKNOWN_NODEID;
-  }
-
-  auto extern_crate =
-      stream == nullptr
-          ? Imports::ExternCrate(crate_name,
-                                 proc_macros) // Import proc macros
-          : Imports::ExternCrate(*stream);    // Import from stream
-  if (stream != nullptr) {
-    bool ok = extern_crate.load(locus);
-    if (!ok) {
-      rust_error_at(locus, "failed to load crate metadata");
+    package_result;
+  if (cli_extern_crate != extern_crates.end ())
+    {
+      auto path = cli_extern_crate->second;
+      package_result = Import::try_package_in_directory (path, locus);
+    }
+  else
+    {
+      package_result
+       = Import::open_package (import_name, locus, relative_import_path);
+    }
+
+  auto stream = std::move (package_result.first);
+  auto proc_macros = std::move (package_result.second);
+
+  if (stream == NULL          // No stream and
+      && proc_macros.empty ()) // no proc macros
+    {
+      rust_error_at (locus, "failed to locate crate %<%s%>",
+                    import_name.c_str ());
       return UNKNOWN_NODEID;
     }
-  }
+
+  auto extern_crate
+    = stream == nullptr
+       ? Imports::ExternCrate (crate_name,
+                               proc_macros) // Import proc macros
+       : Imports::ExternCrate (*stream);    // Import from stream
+  if (stream != nullptr)
+    {
+      bool ok = extern_crate.load (locus);
+      if (!ok)
+       {
+         rust_error_at (locus, "failed to load crate metadata");
+         return UNKNOWN_NODEID;
+       }
+    }
 
   // ensure the current vs this crate name don't collide
-  const std::string current_crate_name = mappings->get_current_crate_name();
-  if (current_crate_name.compare(extern_crate.get_crate_name()) == 0) {
-    rust_error_at(locus, "current crate name %<%s%> collides with this",
-                  current_crate_name.c_str());
-    return UNKNOWN_NODEID;
-  }
+  const std::string current_crate_name = mappings->get_current_crate_name ();
+  if (current_crate_name.compare (extern_crate.get_crate_name ()) == 0)
+    {
+      rust_error_at (locus, "current crate name %<%s%> collides with this",
+                    current_crate_name.c_str ());
+      return UNKNOWN_NODEID;
+    }
 
   // setup mappings
-  CrateNum saved_crate_num = mappings->get_current_crate();
-  CrateNum crate_num =
-      mappings->get_next_crate_num(extern_crate.get_crate_name());
-  mappings->set_current_crate(crate_num);
+  CrateNum saved_crate_num = mappings->get_current_crate ();
+  CrateNum crate_num
+    = mappings->get_next_crate_num (extern_crate.get_crate_name ());
+  mappings->set_current_crate (crate_num);
 
   // then lets parse this as a 2nd crate
-  Lexer lex(extern_crate.get_metadata(), linemap);
-  Parser<Lexer> parser(lex);
-  std::unique_ptr<AST::Crate> metadata_crate = parser.parse_crate();
+  Lexer lex (extern_crate.get_metadata (), linemap);
+  Parser<Lexer> parser (lex);
+  std::unique_ptr<AST::Crate> metadata_crate = parser.parse_crate ();
 
-  AST::Crate &parsed_crate =
-      mappings->insert_ast_crate(std::move(metadata_crate), crate_num);
+  AST::Crate &parsed_crate
+    = mappings->insert_ast_crate (std::move (metadata_crate), crate_num);
 
   std::vector<AttributeProcMacro> attribute_macros;
   std::vector<CustomDeriveProcMacro> derive_macros;
   std::vector<BangProcMacro> bang_macros;
 
-  for (auto &macro : extern_crate.get_proc_macros()) {
-    switch (macro.tag) {
-    case ProcMacro::CUSTOM_DERIVE:
-      derive_macros.push_back(macro.payload.custom_derive);
-      break;
-    case ProcMacro::ATTR:
-      attribute_macros.push_back(macro.payload.attribute);
-      break;
-    case ProcMacro::BANG:
-      bang_macros.push_back(macro.payload.bang);
-      break;
-    default:
-      gcc_unreachable();
+  for (auto &macro : extern_crate.get_proc_macros ())
+    {
+      switch (macro.tag)
+       {
+       case ProcMacro::CUSTOM_DERIVE:
+         derive_macros.push_back (macro.payload.custom_derive);
+         break;
+       case ProcMacro::ATTR:
+         attribute_macros.push_back (macro.payload.attribute);
+         break;
+       case ProcMacro::BANG:
+         bang_macros.push_back (macro.payload.bang);
+         break;
+       default:
+         gcc_unreachable ();
+       }
     }
-  }
 
-  mappings->insert_attribute_proc_macros(crate_num, attribute_macros);
-  mappings->insert_bang_proc_macros(crate_num, bang_macros);
-  mappings->insert_derive_proc_macros(crate_num, derive_macros);
+  mappings->insert_attribute_proc_macros (crate_num, attribute_macros);
+  mappings->insert_bang_proc_macros (crate_num, bang_macros);
+  mappings->insert_derive_proc_macros (crate_num, derive_macros);
 
   // name resolve it
-  Resolver::NameResolution::Resolve(parsed_crate);
+  Resolver::NameResolution::Resolve (parsed_crate);
 
   // perform hir lowering
-  std::unique_ptr<HIR::Crate> lowered = HIR::ASTLowering::Resolve(parsed_crate);
-  HIR::Crate &hir = mappings->insert_hir_crate(std::move(lowered));
+  std::unique_ptr<HIR::Crate> lowered
+    = HIR::ASTLowering::Resolve (parsed_crate);
+  HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered));
 
   // perform type resolution
-  Resolver::TypeResolution::Resolve(hir);
+  Resolver::TypeResolution::Resolve (hir);
 
   // always restore the crate_num
-  mappings->set_current_crate(saved_crate_num);
+  mappings->set_current_crate (saved_crate_num);
 
-  return parsed_crate.get_node_id();
+  return parsed_crate.get_node_id ();
 }
 //
 
-void TargetOptions::dump_target_options() const {
+void
+TargetOptions::dump_target_options () const
+{
   std::ofstream out;
-  out.open(kTargetOptionsDumpFile);
-  if (out.fail()) {
-    rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
-                  kTargetOptionsDumpFile);
-    return;
-  }
+  out.open (kTargetOptionsDumpFile);
+  if (out.fail ())
+    {
+      rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+                    kTargetOptionsDumpFile);
+      return;
+    }
 
-  if (features.empty()) {
-    out << "No target options available!\n";
-  }
+  if (features.empty ())
+    {
+      out << "No target options available!\n";
+    }
 
-  for (const auto &pairs : features) {
-    for (const auto &value : pairs.second) {
-      if (value.has_value())
-        out << pairs.first + ": \"" + value.value() + "\"\n";
-      else
-        out << pairs.first + "\n";
+  for (const auto &pairs : features)
+    {
+      for (const auto &value : pairs.second)
+       {
+         if (value.has_value ())
+           out << pairs.first + ": \"" + value.value () + "\"\n";
+         else
+           out << pairs.first + "\n";
+       }
     }
-  }
 
-  out.close();
+  out.close ();
 }
 
-void TargetOptions::init_derived_values() {
+void
+TargetOptions::init_derived_values ()
+{
   // enable derived values based on target families
-  if (has_key_value_pair("target_family", "unix"))
-    insert_key("unix");
-  if (has_key_value_pair("target_family", "windows"))
-    insert_key("windows");
+  if (has_key_value_pair ("target_family", "unix"))
+    insert_key ("unix");
+  if (has_key_value_pair ("target_family", "windows"))
+    insert_key ("windows");
 
   // implicitly enable features - this should not be required in general
-  if (has_key_value_pair("target_feature", "aes"))
-    enable_implicit_feature_reqs("aes");
-  if (has_key_value_pair("target_feature", "avx"))
-    enable_implicit_feature_reqs("sse4.2");
-  if (has_key_value_pair("target_feature", "avx2"))
-    enable_implicit_feature_reqs("avx");
-  if (has_key_value_pair("target_feature", "pclmulqdq"))
-    enable_implicit_feature_reqs("sse2");
-  if (has_key_value_pair("target_feature", "sha"))
-    enable_implicit_feature_reqs("sse2");
-  if (has_key_value_pair("target_feature", "sse2"))
-    enable_implicit_feature_reqs("sse");
-  if (has_key_value_pair("target_feature", "sse3"))
-    enable_implicit_feature_reqs("sse2");
-  if (has_key_value_pair("target_feature", "sse4.1"))
-    enable_implicit_feature_reqs("sse3");
-  if (has_key_value_pair("target_feature", "sse4.2"))
-    enable_implicit_feature_reqs("sse4.1");
-  if (has_key_value_pair("target_feature", "ssse3"))
-    enable_implicit_feature_reqs("sse3");
+  if (has_key_value_pair ("target_feature", "aes"))
+    enable_implicit_feature_reqs ("aes");
+  if (has_key_value_pair ("target_feature", "avx"))
+    enable_implicit_feature_reqs ("sse4.2");
+  if (has_key_value_pair ("target_feature", "avx2"))
+    enable_implicit_feature_reqs ("avx");
+  if (has_key_value_pair ("target_feature", "pclmulqdq"))
+    enable_implicit_feature_reqs ("sse2");
+  if (has_key_value_pair ("target_feature", "sha"))
+    enable_implicit_feature_reqs ("sse2");
+  if (has_key_value_pair ("target_feature", "sse2"))
+    enable_implicit_feature_reqs ("sse");
+  if (has_key_value_pair ("target_feature", "sse3"))
+    enable_implicit_feature_reqs ("sse2");
+  if (has_key_value_pair ("target_feature", "sse4.1"))
+    enable_implicit_feature_reqs ("sse3");
+  if (has_key_value_pair ("target_feature", "sse4.2"))
+    enable_implicit_feature_reqs ("sse4.1");
+  if (has_key_value_pair ("target_feature", "ssse3"))
+    enable_implicit_feature_reqs ("sse3");
 }
 
-void TargetOptions::enable_implicit_feature_reqs(std::string feature) {
+void
+TargetOptions::enable_implicit_feature_reqs (std::string feature)
+{
   if (feature == "aes")
-    enable_implicit_feature_reqs("sse2");
+    enable_implicit_feature_reqs ("sse2");
   else if (feature == "avx")
-    enable_implicit_feature_reqs("sse4.2");
+    enable_implicit_feature_reqs ("sse4.2");
   else if (feature == "avx2")
-    enable_implicit_feature_reqs("avx");
+    enable_implicit_feature_reqs ("avx");
   else if (feature == "fma")
-    enable_implicit_feature_reqs("avx");
+    enable_implicit_feature_reqs ("avx");
   else if (feature == "pclmulqdq")
-    enable_implicit_feature_reqs("sse2");
+    enable_implicit_feature_reqs ("sse2");
   else if (feature == "sha")
-    enable_implicit_feature_reqs("sse2");
+    enable_implicit_feature_reqs ("sse2");
   else if (feature == "sse2")
-    enable_implicit_feature_reqs("sse");
+    enable_implicit_feature_reqs ("sse");
   else if (feature == "sse3")
-    enable_implicit_feature_reqs("sse2");
+    enable_implicit_feature_reqs ("sse2");
   else if (feature == "sse4.1")
-    enable_implicit_feature_reqs("sse3");
+    enable_implicit_feature_reqs ("sse3");
   else if (feature == "sse4.2")
-    enable_implicit_feature_reqs("sse4.1");
+    enable_implicit_feature_reqs ("sse4.1");
   else if (feature == "ssse3")
-    enable_implicit_feature_reqs("sse3");
+    enable_implicit_feature_reqs ("sse3");
 
-  if (!has_key_value_pair("target_feature", feature)) {
-    insert_key_value_pair("target_feature", feature);
+  if (!has_key_value_pair ("target_feature", feature))
+    {
+      insert_key_value_pair ("target_feature", feature);
 
-    rust_debug("had to implicitly enable feature '%s'!", feature.c_str());
-  }
+      rust_debug ("had to implicitly enable feature '%s'!", feature.c_str ());
+    }
 }
 
 // NOTEs:
@@ -1180,32 +1324,34 @@ void TargetOptions::enable_implicit_feature_reqs(std::string feature) {
 
 #if CHECKING_P
 namespace selftest {
-void rust_crate_name_validation_test(void) {
-  auto error = Rust::Error(UNDEF_LOCATION, std::string());
-  ASSERT_TRUE(Rust::validate_crate_name("example", error));
-  ASSERT_TRUE(Rust::validate_crate_name("abcdefg_1234", error));
-  ASSERT_TRUE(Rust::validate_crate_name("1", error));
-  ASSERT_TRUE(Rust::validate_crate_name("クレート", error));
-  ASSERT_TRUE(Rust::validate_crate_name("Sōkrátēs", error));
-  ASSERT_TRUE(Rust::validate_crate_name("惊吓", error));
+void
+rust_crate_name_validation_test (void)
+{
+  auto error = Rust::Error (UNDEF_LOCATION, std::string ());
+  ASSERT_TRUE (Rust::validate_crate_name ("example", error));
+  ASSERT_TRUE (Rust::validate_crate_name ("abcdefg_1234", error));
+  ASSERT_TRUE (Rust::validate_crate_name ("1", error));
+  ASSERT_TRUE (Rust::validate_crate_name ("クレート", error));
+  ASSERT_TRUE (Rust::validate_crate_name ("Sōkrátēs", error));
+  ASSERT_TRUE (Rust::validate_crate_name ("惊吓", error));
 
   // NOTE: - is not allowed in the crate name ...
 
-  ASSERT_FALSE(Rust::validate_crate_name("abcdefg-1234", error));
-  ASSERT_FALSE(Rust::validate_crate_name("a+b", error));
-  ASSERT_FALSE(Rust::validate_crate_name("/a+b/", error));
-  ASSERT_FALSE(Rust::validate_crate_name("😸++", error));
-  ASSERT_FALSE(Rust::validate_crate_name("∀", error));
+  ASSERT_FALSE (Rust::validate_crate_name ("abcdefg-1234", error));
+  ASSERT_FALSE (Rust::validate_crate_name ("a+b", error));
+  ASSERT_FALSE (Rust::validate_crate_name ("/a+b/", error));
+  ASSERT_FALSE (Rust::validate_crate_name ("😸++", error));
+  ASSERT_FALSE (Rust::validate_crate_name ("∀", error));
 
   /* Tests for crate name inference */
-  ASSERT_EQ(Rust::infer_crate_name("c.rs"), "c");
+  ASSERT_EQ (Rust::infer_crate_name ("c.rs"), "c");
   // NOTE: ... but - is allowed when in the filename
-  ASSERT_EQ(Rust::infer_crate_name("a-b.rs"), "a_b");
-  ASSERT_EQ(Rust::infer_crate_name("book.rs.txt"), "book.rs");
+  ASSERT_EQ (Rust::infer_crate_name ("a-b.rs"), "a_b");
+  ASSERT_EQ (Rust::infer_crate_name ("book.rs.txt"), "book.rs");
 #if defined(HAVE_DOS_BASED_FILE_SYSTEM)
-  ASSERT_EQ(Rust::infer_crate_name("a\\c\\a-b.rs"), "a_b");
+  ASSERT_EQ (Rust::infer_crate_name ("a\\c\\a-b.rs"), "a_b");
 #else
-  ASSERT_EQ(Rust::infer_crate_name("a/c/a-b.rs"), "a_b");
+  ASSERT_EQ (Rust::infer_crate_name ("a/c/a-b.rs"), "a_b");
 #endif
 }
 } // namespace selftest