https://gcc.gnu.org/g:9a45588f39d9710f2d7b5dec2e75d00531e7436d
commit 9a45588f39d9710f2d7b5dec2e75d00531e7436d Author: Jakub Dupak <d...@jakubdupak.com> Date: Wed Oct 18 20:43:17 2023 +0200 borrowck: Create BIR builders (visitors) 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 <d...@jakubdupak.com> Diff: --- gcc/rust/Make-lang.in | 1 + .../errors/borrowck/rust-bir-builder-expr-stmt.cc | 578 +++++++++++++++++++++ .../errors/borrowck/rust-bir-builder-expr-stmt.h | 150 ++++++ .../errors/borrowck/rust-bir-builder-internal.h | 416 +++++++++++++++ .../borrowck/rust-bir-builder-lazyboolexpr.h | 243 +++++++++ .../errors/borrowck/rust-bir-builder-pattern.h | 290 +++++++++++ .../errors/borrowck/rust-bir-builder-struct.h | 270 ++++++++++ gcc/rust/checks/errors/borrowck/rust-bir-builder.h | 88 ++++ .../checks/errors/borrowck/rust-borrow-checker.cc | 8 +- gcc/rust/rust-session-manager.cc | 2 +- 10 files changed, 2042 insertions(+), 4 deletions(-) diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index f4b9eb5502e2..1e462ef6a1bf 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -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 index 000000000000..1487c853b49e --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -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 index 000000000000..f46cba5f9684 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -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 index 000000000000..48116d8c351c --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -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 index 000000000000..4ec87d9c71e6 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -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 index 000000000000..0b4c83eca844 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h @@ -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 index 000000000000..fa2f5965af68 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -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 ¶m) override { rust_unreachable (); } + void visit (HIR::ConstGenericParam ¶m) 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 index 000000000000..322d00d280e5 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h @@ -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 ¶m : 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 ¶m) + { + 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 diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc index 44d33c57838a..4b9712538df3 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc @@ -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 ()) diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 96d5f4729165..c18a3d01bd94 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -46,12 +46,12 @@ #include "rust-expand-visitor.h" #include "rust-unicode.h" #include "rust-attribute-values.h" +#include "rust-borrow-checker.h" #include "input.h" #include "selftest.h" #include "tm.h" #include "rust-target.h" -#include "rust-borrow-checker.h" extern bool saw_errors (void);