From 2a1a37344f0db01900e73f05fca71cdcf7a559c2 Mon Sep 17 00:00:00 2001 From: Jakub Dupak Date: Thu, 19 Oct 2023 15:26:35 +0200 Subject: [PATCH] borrowck: Refactor and BIR improvements gcc/rust/ChangeLog: * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::setup_loop): Move. (ExprStmtBuilder::get_label_ctx): Move. (ExprStmtBuilder::get_unnamed_loop_ctx): Moved. (ExprStmtBuilder::visit): BIR improvements. * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Refactor. * checks/errors/borrowck/rust-bir-builder-internal.h (class LifetimeResolver): Refactor. (struct BuilderContext): Move.Refactor. (optional_from_ptr): Map on null ptr. * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h (class LazyBooleanExprBuilder): Refactor. * checks/errors/borrowck/rust-bir-builder-pattern.h: Refactor. * checks/errors/borrowck/rust-bir-builder-struct.h (class StructBuilder): Refactor. * checks/errors/borrowck/rust-bir-builder.h: Refactor. * checks/errors/borrowck/rust-bir-dump.cc (Dump::go): Refactor. (Dump::visit): Refactor. (Dump::visit_place): Refactor. (Dump::visit_move_place): Refactor. (Dump::visit_lifetime): Refactor. * checks/errors/borrowck/rust-bir-dump.h: Refactor. * checks/errors/borrowck/rust-bir-place.h: Refactor. Signed-off-by: Jakub Dupak --- .../borrowck/rust-bir-builder-expr-stmt.cc | 285 ++++++++-------- .../borrowck/rust-bir-builder-expr-stmt.h | 28 +- .../borrowck/rust-bir-builder-internal.h | 319 ++++++++++-------- .../borrowck/rust-bir-builder-lazyboolexpr.h | 89 +++-- .../borrowck/rust-bir-builder-pattern.h | 36 +- .../errors/borrowck/rust-bir-builder-struct.h | 22 +- .../checks/errors/borrowck/rust-bir-builder.h | 10 +- .../checks/errors/borrowck/rust-bir-dump.cc | 57 ++-- .../checks/errors/borrowck/rust-bir-dump.h | 5 +- .../checks/errors/borrowck/rust-bir-place.h | 72 ++-- 10 files changed, 508 insertions(+), 415 deletions(-) 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 index 367aea7c2da3..96bc738964ed 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -25,6 +25,48 @@ namespace Rust { namespace BIR { +using LoopAndLabelCtx = BuilderContext::LoopAndLabelCtx; + +BuilderContext::LoopAndLabelCtx & +ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr) +{ + NodeId label + = (expr.has_loop_label ()) + ? expr.get_loop_label ().get_lifetime ().get_mappings ().get_nodeid () + : UNKNOWN_NODEID; + PlaceId label_var = take_or_create_return_place (lookup_type (expr)); + + BasicBlockId continue_bb = new_bb (); + BasicBlockId break_bb = new_bb (); + ctx.loop_and_label_stack.push_back ( + {true, label, label_var, break_bb, continue_bb}); + return ctx.loop_and_label_stack.back (); +} + +BuilderContext::LoopAndLabelCtx & +ExprStmtBuilder::get_label_ctx (HIR::Lifetime &label) +{ + NodeId label_id = resolve_label (label); + auto lookup = std::find_if (ctx.loop_and_label_stack.rbegin (), + ctx.loop_and_label_stack.rend (), + [label_id] (LoopAndLabelCtx &info) { + return info.label == label_id; + }); + rust_assert (lookup != ctx.loop_and_label_stack.rend ()); + return *lookup; +} + +LoopAndLabelCtx & +ExprStmtBuilder::get_unnamed_loop_ctx () +{ + auto lookup + = std::find_if (ctx.loop_and_label_stack.rbegin (), + ctx.loop_and_label_stack.rend (), + [] (LoopAndLabelCtx &info) { return info.is_loop; }); + rust_assert (lookup != ctx.loop_and_label_stack.rend ()); + return *lookup; +} + void ExprStmtBuilder::visit (HIR::ClosureExpr &expr) { @@ -34,8 +76,9 @@ ExprStmtBuilder::visit (HIR::ClosureExpr &expr) { captures.push_back (ctx.place_db.lookup_variable (capture)); } + make_args (captures); - // Not a coercion site. + // Note: Not a coercion site for captures. return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr)); } @@ -45,6 +88,7 @@ ExprStmtBuilder::visit (HIR::StructExprStructFields &fields) auto struct_ty = lookup_type (fields)->as ()->get_variants ().at (0); auto init_values = StructBuilder (ctx, struct_ty).build (fields); + make_args (init_values); return_expr (new InitializerExpr (std::move (init_values)), lookup_type (fields)); } @@ -59,7 +103,7 @@ ExprStmtBuilder::visit (HIR::StructExprStruct &expr) void ExprStmtBuilder::visit (HIR::LiteralExpr &expr) { - // Different literal values of the same type are not distinguished. + // Different literal values of the same type are not distinguished in BIR. return_place (ctx.place_db.get_constant (lookup_type (expr))); } @@ -74,12 +118,14 @@ void ExprStmtBuilder::visit (HIR::DereferenceExpr &expr) { auto operand = visit_expr (*expr.get_expr ()); - return_place (operand); + return_place (ctx.place_db.lookup_or_add_path (Place::DEREF, + lookup_type (expr), operand)); } void ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr) { + // TODO: desugar in AST->HIR rust_sorry_at (expr.get_locus (), "error propagation is not supported"); } @@ -87,7 +133,7 @@ void ExprStmtBuilder::visit (HIR::NegationExpr &expr) { PlaceId operand = visit_expr (*expr.get_expr ()); - return_expr (new Operator<1> ({operand}), lookup_type (expr)); + return_expr (new Operator<1> ({make_arg (operand)}), lookup_type (expr)); } void @@ -95,7 +141,8 @@ 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)); + return_expr (new Operator<2> ({make_arg (lhs), make_arg (rhs)}), + lookup_type (expr)); } void @@ -103,19 +150,23 @@ 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)); + return_expr (new Operator<2> ({make_arg (lhs), make_arg (rhs)}), + lookup_type (expr)); } void ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr) { - return_place (LazyBooleanExprBuilder (ctx).build (expr)); + return_place (LazyBooleanExprBuilder (ctx, take_or_create_return_place ( + lookup_type (expr))) + .build (expr)); } void ExprStmtBuilder::visit (HIR::TypeCastExpr &expr) { - return_place (visit_expr (*expr.get_expr ())); + auto operand = visit_expr (*expr.get_expr ()); + return_expr (new Operator<1> ({operand}), lookup_type (expr)); } void @@ -132,34 +183,31 @@ 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); + return_place (visit_expr (*expr.get_expr_in_parens ())); } void ExprStmtBuilder::visit (HIR::ArrayExpr &expr) { - switch (expr.get_internal_elements ()->get_array_expr_type ()) + auto &elems = expr.get_internal_elements (); + switch (elems->get_array_expr_type ()) { case HIR::ArrayElems::VALUES: { - auto init_values = visit_list ((static_cast ( - expr.get_internal_elements ().get ())) - ->get_values ()); + auto &elem_vals = (static_cast (*elems)); + auto init_values = visit_list (elem_vals.get_values ()); + make_args (init_values); return_expr (new InitializerExpr (std::move (init_values)), lookup_type (expr)); break; } case HIR::ArrayElems::COPIED: { - auto init = visit_expr (*(static_cast ( - expr.get_internal_elements ().get ())) - ->get_elem_to_copy ()); + auto &elem_copied = (static_cast (*elems)); + auto init = visit_expr (*elem_copied.get_elem_to_copy ()); return_expr (new InitializerExpr ({init}), lookup_type (expr)); break; } @@ -171,7 +219,7 @@ 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. + // The index is not tracked in BIR. (void) rhs; return_place ( ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs)); @@ -181,14 +229,6 @@ void ExprStmtBuilder::visit (HIR::TupleExpr &expr) { std::vector 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)); } @@ -208,7 +248,7 @@ ExprStmtBuilder::visit (HIR::CallExpr &expr) PlaceId fn = visit_expr (*expr.get_fnexpr ()); std::vector arguments = visit_list (expr.get_arguments ()); - TyTy::BaseType *call_type = ctx.place_db[fn].tyty; + auto *call_type = ctx.place_db[fn].tyty; if (auto fn_type = call_type->try_as ()) { for (size_t i = 0; i < fn_type->get_params ().size (); ++i) @@ -233,6 +273,10 @@ ExprStmtBuilder::visit (HIR::CallExpr &expr) true); } +void +ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) +{} + void ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) { @@ -242,12 +286,12 @@ ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) auto adt = type->as (); rust_assert (!adt->is_enum ()); rust_assert (adt->number_of_variants () == 1); - TyTy::VariantDef *variant = adt->get_variants ().at (0); + auto struct_ty = 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); + bool ok = struct_ty->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, @@ -258,114 +302,71 @@ ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) void ExprStmtBuilder::visit (HIR::BlockExpr &block) { - BasicBlockId end_bb; - if (block.has_label ()) { - end_bb = new_bb (); NodeId label = block.get_label ().get_lifetime ().get_mappings ().get_nodeid (); - PlaceId label_var = ctx.place_db.add_temporary (lookup_type (block)); - ctx.loop_and_label_stack.push_back ({false, label, label_var, end_bb, 0}); + PlaceId label_var = take_or_create_return_place (lookup_type (block)); + ctx.loop_and_label_stack.push_back ( + {false, label, label_var, new_bb (), INVALID_BB}); } + // Eliminates dead code after break, continue, return. bool unreachable = false; for (auto &stmt : block.get_statements ()) { - if (unreachable) - break; stmt->accept_vis (*this); if (ctx.get_current_bb ().is_terminated ()) - unreachable = true; + { + unreachable = true; + break; + } } if (block.has_label ()) { - auto label_info = ctx.loop_and_label_stack.back (); + auto block_ctx = ctx.loop_and_label_stack.back (); if (block.has_expr () && !unreachable) { - push_assignment (label_info.label_var, + push_assignment (block_ctx.label_var, visit_expr (*block.get_final_expr ())); } if (!ctx.get_current_bb ().is_terminated ()) { - add_jump_to (end_bb); + push_goto (block_ctx.break_bb); } - ctx.current_bb = end_bb; + ctx.current_bb = block_ctx.break_bb; ctx.loop_and_label_stack.pop_back (); - return_place (label_info.label_var); + return_place (block_ctx.label_var); } else if (block.has_expr () && !unreachable) { - return_place (visit_expr (*block.get_final_expr ())); + return_place (visit_expr (*block.get_final_expr (), + take_or_create_return_place ( + lookup_type (*block.get_final_expr ())))); } } void ExprStmtBuilder::visit (HIR::ContinueExpr &cont) { - BuilderContext::LoopAndLabelInfo info; - if (cont.has_label ()) - { - NodeId label = resolve_label (cont.get_label ()); - auto lookup - = std::find_if (ctx.loop_and_label_stack.rbegin (), - ctx.loop_and_label_stack.rend (), - [label] (const BuilderContext::LoopAndLabelInfo &info) { - return info.label == label; - }); - rust_assert (lookup != ctx.loop_and_label_stack.rend ()); - info = *lookup; - } - else - { - auto lookup - = std::find_if (ctx.loop_and_label_stack.rbegin (), - ctx.loop_and_label_stack.rend (), - [] (const BuilderContext::LoopAndLabelInfo &info) { - return info.is_loop; - }); - rust_assert (lookup != ctx.loop_and_label_stack.rend ()); - info = *lookup; - } + LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ()) + : get_unnamed_loop_ctx (); push_goto (info.continue_bb); - // No code allowed after continue. No BB starts - would be empty. + // No code allowed after continue. Handled in BlockExpr. } void ExprStmtBuilder::visit (HIR::BreakExpr &brk) { - BuilderContext::LoopAndLabelInfo info; - if (brk.has_label ()) - { - NodeId label = resolve_label (brk.get_label ()); - auto lookup - = std::find_if (ctx.loop_and_label_stack.rbegin (), - ctx.loop_and_label_stack.rend (), - [label] (const BuilderContext::LoopAndLabelInfo &info) { - return info.label == label; - }); - rust_assert (lookup != ctx.loop_and_label_stack.rend ()); - info = *lookup; - } - else - { - auto lookup - = std::find_if (ctx.loop_and_label_stack.rbegin (), - ctx.loop_and_label_stack.rend (), - [] (const BuilderContext::LoopAndLabelInfo &info) { - return info.is_loop; - }); - rust_assert (lookup != ctx.loop_and_label_stack.rend ()); - info = *lookup; - } + LoopAndLabelCtx info = brk.has_label () ? get_label_ctx (brk.get_label ()) + : get_unnamed_loop_ctx (); if (brk.has_break_expr ()) - { - push_assignment (info.label_var, visit_expr (*brk.get_expr ())); - } + push_assignment (info.label_var, visit_expr (*brk.get_expr ())); + push_goto (info.break_bb); - // No code allowed after break. No BB starts - would be empty. + // No code allowed after continue. Handled in BlockExpr. } void @@ -427,22 +428,6 @@ ExprStmtBuilder::visit (HIR::UnsafeBlockExpr &expr) rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported"); } -BuilderContext::LoopAndLabelInfo & -ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr) -{ - NodeId label - = (expr.has_loop_label ()) - ? expr.get_loop_label ().get_lifetime ().get_mappings ().get_nodeid () - : UNKNOWN_NODEID; - PlaceId label_var = ctx.place_db.add_temporary (lookup_type (expr)); - - BasicBlockId continue_bb = new_bb (); - BasicBlockId break_bb = new_bb (); - ctx.loop_and_label_stack.push_back ( - {true, label, label_var, break_bb, continue_bb}); - return ctx.loop_and_label_stack.back (); -} - void ExprStmtBuilder::visit (HIR::LoopExpr &expr) { @@ -518,40 +503,40 @@ ExprStmtBuilder::visit (HIR::IfExpr &expr) void ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr) { - PlaceId result = ctx.place_db.add_temporary (lookup_type (expr)); + push_switch (make_arg (visit_expr (*expr.get_if_condition ()))); + BasicBlockId if_end_bb = ctx.current_bb; - push_switch (visit_expr (*expr.get_if_condition ())); - BasicBlockId if_block = ctx.current_bb; + PlaceId result = take_or_create_return_place (lookup_type (expr)); ctx.current_bb = new_bb (); - auto then_res = visit_expr (*expr.get_if_block ()); - push_assignment (result, then_res); + BasicBlockId then_start_bb = ctx.current_bb; + (void) visit_expr (*expr.get_if_block (), result); if (!ctx.get_current_bb ().is_terminated ()) push_goto (INVALID_BB); // Resolved later. - BasicBlockId then_block = ctx.current_bb; + BasicBlockId then_end_bb = ctx.current_bb; ctx.current_bb = new_bb (); - auto else_res = visit_expr (*expr.get_else_block ()); - push_assignment (result, else_res); + BasicBlockId else_start_bb = ctx.current_bb; + (void) visit_expr (*expr.get_else_block (), result); if (!ctx.get_current_bb ().is_terminated ()) push_goto (INVALID_BB); // Resolved later. - BasicBlockId else_block = ctx.current_bb; + BasicBlockId else_end_bb = ctx.current_bb; ctx.current_bb = new_bb (); - BasicBlockId final_block = ctx.current_bb; + BasicBlockId final_start_bb = 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 (if_end_bb, then_start_bb); + add_jump (if_end_bb, else_start_bb); - auto &then_bb = ctx.basic_blocks[then_block]; + auto &then_bb = ctx.basic_blocks[then_end_bb]; if (then_bb.is_goto_terminated () && then_bb.successors.empty ()) - add_jump (then_block, final_block); + add_jump (then_end_bb, final_start_bb); - auto &else_bb = ctx.basic_blocks[else_block]; + auto &else_bb = ctx.basic_blocks[else_end_bb]; if (else_bb.is_goto_terminated () && else_bb.successors.empty ()) - add_jump (else_block, final_block); + add_jump (else_end_bb, final_start_bb); } void ExprStmtBuilder::visit (HIR::IfLetExpr &expr) @@ -566,6 +551,7 @@ ExprStmtBuilder::visit (HIR::IfLetExprConseqElse &expr) void ExprStmtBuilder::visit (HIR::MatchExpr &expr) { + rust_sorry_at (expr.get_locus (), "match expressions are not supported"); // // TODO // expr.get_scrutinee_expr ()->accept_vis (*this); // PlaceId scrutinee = translated; @@ -621,44 +607,47 @@ ExprStmtBuilder::visit (HIR::AsyncBlockExpr &expr) 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); + PlaceId result + = resolve_variable_or_fn (expr.get_final_segment (), lookup_type (expr)); 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); + PlaceId result + = resolve_variable_or_fn (expr.get_final_segment (), lookup_type (expr)); 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) + if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER) { + // Only if a pattern is just an identifier, no destructuring is needed. + // Hoverer PatternBindingBuilder cannot change existing temporary + // (init expr is evaluated before pattern binding) into a + // variable, so it would emit extra assignment. 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 ( - static_cast (stmt.get_type ().get ())); var_place.lifetime = ctx.lookup_lifetime ( - p_type.map (&HIR::ReferenceType::get_lifetime)); + optional_from_ptr ( + static_cast (stmt.get_type ().get ())) + .map (&HIR::ReferenceType::get_lifetime)); } - return; + if (stmt.has_init_expr ()) + (void) visit_expr (*stmt.get_init_expr (), var); + } + else 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 { 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 index e5707c31f8d3..1352965b725e 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -25,14 +25,21 @@ namespace Rust { namespace BIR { +/** + * Compiles expressions into a BIR place. + * See AbstractExprBuilder for API usage docs (mainly `return_place` and + * `return_expr`). + */ 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); } + /** Entry point. */ + PlaceId build (HIR::Expr &expr, PlaceId place = INVALID_PLACE) + { + return visit_expr (expr, place); + } private: template @@ -46,17 +53,19 @@ class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor return result; } - BuilderContext::LoopAndLabelInfo &setup_loop (HIR::BaseLoopExpr &expr); + /** Common infrastructure for loops. */ + BuilderContext::LoopAndLabelCtx &setup_loop (HIR::BaseLoopExpr &expr); + + BuilderContext::LoopAndLabelCtx &get_label_ctx (HIR::Lifetime &label); + BuilderContext::LoopAndLabelCtx &get_unnamed_loop_ctx (); 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; @@ -71,7 +80,7 @@ class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor 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::MethodCallExpr &expr) override; void visit (HIR::FieldAccessExpr &expr) override; void visit (HIR::BlockExpr &block) override; void visit (HIR::ContinueExpr &cont) override; @@ -96,7 +105,7 @@ class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor void visit (HIR::AwaitExpr &expr) override; void visit (HIR::AsyncBlockExpr &expr) override; - // Nodes not containing executable code. Nothing to do. +protected: // Nodes not containing executable code. Nothing to do. void visit (HIR::QualifiedPathInExpression &expr) override; void visit (HIR::PathInExpression &expr) override; @@ -119,9 +128,8 @@ class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor void visit (HIR::ExprStmt &stmt) override; -protected: // Unused +protected: // Ignored. // 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 {} diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h index 663b6ad7fae6..f33eb0752446 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -31,31 +31,35 @@ namespace Rust { namespace BIR { -class LifetimeResolver +/** Holds the context of BIR building so that it can be shared/passed between + * different builders. */ +struct BuilderContext { - using Index = uint32_t; - using Value = std::string; + class LifetimeResolver + { + using Index = uint32_t; + using Value = std::string; - Index next_index = FIRST_NORMAL_LIFETIME_ID; - std::unordered_map value_to_index; + Index next_index = FIRST_NORMAL_LIFETIME_ID; + std::unordered_map 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++; } -}; + public: + Index resolve (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++; + } -struct BuilderContext -{ - struct LoopAndLabelInfo + /** Returns a new anonymous lifetime. */ + Index get_anonymous () { return next_index++; } + }; + + struct LoopAndLabelCtx { bool is_loop; // Loop or labelled block NodeId label; // UNKNOWN_NODEID if no label (loop) @@ -63,19 +67,20 @@ struct BuilderContext BasicBlockId break_bb; BasicBlockId continue_bb; // Only valid for loops - LoopAndLabelInfo (bool is_loop = false, NodeId label = UNKNOWN_NODEID, - PlaceId label_var = INVALID_PLACE, - BasicBlockId break_bb = INVALID_BB, - BasicBlockId continue_bb = INVALID_BB) + LoopAndLabelCtx (bool is_loop = false, NodeId label = UNKNOWN_NODEID, + PlaceId label_var = INVALID_PLACE, + BasicBlockId break_bb = INVALID_BB, + BasicBlockId continue_bb = INVALID_BB) : is_loop (is_loop), label (label), label_var (label_var), break_bb (break_bb), continue_bb (continue_bb) {} }; - // Context + // External context. Resolver::TypeCheckContext &tyctx; Resolver::Resolver &resolver; + // BIR output std::vector basic_blocks; size_t current_bb = 0; @@ -85,6 +90,7 @@ struct BuilderContext */ PlaceDB place_db; LifetimeResolver lifetime_interner; + // Used for cleaner dump. std::vector arguments; /** * Since labels can be used to return values, we need to reserve a place for @@ -92,7 +98,8 @@ struct BuilderContext */ std::unordered_map label_place_map; - std::vector loop_and_label_stack; + /** Context for current situation (loop, label, etc.) */ + std::vector loop_and_label_stack; public: BuilderContext () @@ -111,7 +118,7 @@ struct BuilderContext switch (lifetime->get_lifetime_type ()) { case AST::Lifetime::NAMED: { - return {lifetime_interner.intern (lifetime->get_name ())}; + return {lifetime_interner.resolve (lifetime->get_name ())}; } case AST::Lifetime::STATIC: { return STATIC_LIFETIME; @@ -125,9 +132,9 @@ struct BuilderContext rust_unreachable (); }; - const LoopAndLabelInfo &lookup_label (NodeId label) + const LoopAndLabelCtx &lookup_label (NodeId label) { - auto label_match = [label] (const LoopAndLabelInfo &info) { + auto label_match = [label] (const LoopAndLabelCtx &info) { return info.label != UNKNOWN_NODEID && info.label == label; }; @@ -138,67 +145,39 @@ struct BuilderContext } }; -// Common infrastructure for building BIR from HIR. +/** 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. + /** + * 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 - 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)); + return declare_variable (node, lookup_type (node.get_hirid ())); } PlaceId declare_variable (const Analysis::NodeMapping &node, - TyTy::BaseType *type) + TyTy::BaseType *ty) { const NodeId nodeid = node.get_nodeid (); - // In debug mode check that the variable is not already declared. + // 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); + return ctx.place_db.add_variable (nodeid, ty); } +protected: // Helpers to add BIR nodes void push_assignment (PlaceId lhs, AbstractExpr *rhs) { ctx.get_current_bb ().statements.emplace_back (lhs, rhs); @@ -219,8 +198,8 @@ class AbstractBuilder void push_switch (PlaceId switch_val, std::initializer_list destinations = {}) { - ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH, - switch_val); + auto copy = make_arg (switch_val); + ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH, copy); ctx.get_current_bb ().successors.insert ( ctx.get_current_bb ().successors.end (), destinations); } @@ -232,25 +211,40 @@ class AbstractBuilder ctx.get_current_bb ().successors.push_back (bb); } - void push_storage_dead (PlaceId place) + PlaceId declare_rvalue (PlaceId place) + { + ctx.place_db[place].is_rvalue = true; + return place; + } + + void declare_rvalues (std::vector &places) + { + for (auto &place : places) + declare_rvalue (place); + } + + PlaceId make_arg (PlaceId arg) { - ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_DEAD, - place); + auto copy = ctx.place_db.into_rvalue (arg); + if (copy != arg) + push_assignment (copy, arg); + return copy; } - void push_storage_live (PlaceId place) + void make_args (std::vector &args) { - ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_LIVE, - place); + std::transform (args.begin (), args.end (), args.begin (), + [this] (PlaceId arg) { return make_arg (arg); }); } +protected: // CFG helpers BasicBlockId new_bb () { ctx.basic_blocks.emplace_back (); return ctx.basic_blocks.size () - 1; } - BasicBlockId start_new_subsequent_bb () + BasicBlockId start_new_consecutive_bb () { BasicBlockId bb = new_bb (); ctx.get_current_bb ().successors.emplace_back (bb); @@ -265,7 +259,22 @@ class AbstractBuilder void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); } -protected: +protected: // HIR resolution helpers + template + [[nodiscard]] TyTy::BaseType *lookup_type (T &hir_node) const + { + return lookup_type (hir_node.get_mappings ().get_hirid ()); + } + + [[nodiscard]] 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; + } + template NodeId resolve_label (T &expr) { NodeId resolved_label; @@ -276,42 +285,30 @@ class AbstractBuilder return resolved_label; } - template - bool resolve_variable (T &variable, PlaceId &resolved_variable) + template PlaceId resolve_variable (T &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 ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + return ctx.place_db.lookup_variable (variable_id); } - bool find_block_ctx (NodeId label, BuilderContext::LoopAndLabelInfo &block) + template + PlaceId resolve_variable_or_fn (T &variable, TyTy::BaseType *ty) { - if (ctx.loop_and_label_stack.empty ()) - return false; - if (label == UNKNOWN_NODEID) - { - block = ctx.loop_and_label_stack.back (); - return true; - } - auto found - = std::find_if (ctx.loop_and_label_stack.rbegin (), - ctx.loop_and_label_stack.rend (), - [&label] (const BuilderContext::LoopAndLabelInfo &block) { - return block.label == label; - }); - if (found == ctx.loop_and_label_stack.rend ()) - return false; - block = *found; - return true; + // Unlike variables, + // functions do not have to be declared in PlaceDB before use. + NodeId variable_id; + bool ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + return ctx.place_db.lookup_or_add_variable (variable_id, + (ty) ? ty + : lookup_type (variable)); } +protected: // Implicit conversions. /** * Performs implicit coercions on the `translated` place defined for a * coercion site. @@ -362,7 +359,6 @@ class AbstractBuilder return ty; } - /** For operator */ void autoref () { if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF) @@ -380,67 +376,108 @@ class AbstractExprBuilder : public AbstractBuilder, public HIR::HIRExpressionVisitor { protected: - // Exactly one of this and `translated` is used by each visitor. - AbstractExpr *expr_return_expr = nullptr; + /** + * Optional place for the result of the evaluated expression. + * Valid if value is not `INVALID_PLACE`. + * Used when return place must be created by caller (return for if-else). + */ + PlaceId expr_return_place = INVALID_PLACE; protected: - explicit AbstractExprBuilder (BuilderContext &ctx) : AbstractBuilder (ctx) {} + explicit AbstractExprBuilder (BuilderContext &ctx, + PlaceId expr_return_place = INVALID_PLACE) + : AbstractBuilder (ctx), expr_return_place (expr_return_place) + {} - PlaceId visit_expr (HIR::Expr &expr) + /** + * Wrapper that provides return value based API inside a visitor which has to + * use global state to pass the data around. + * @param dst_place Place to assign the produced value to, optionally + * allocated by the caller. + * */ + PlaceId visit_expr (HIR::Expr &expr, PlaceId dst_place = INVALID_PLACE) { - // Reset return places. + // Save to support proper recursion. + auto saved = expr_return_place; + expr_return_place = dst_place; translated = INVALID_PLACE; - expr_return_expr = nullptr; expr.accept_vis (*this); - if (translated != INVALID_PLACE) + expr_return_place = saved; + auto result = translated; + translated = INVALID_PLACE; + return result; + } + + /** + * Create a return value of a subexpression, which produces an expression. + * Use `return_place` for subexpression that only produce a place (look it up) + * to avoid needless assignments. + * + * @param can_panic mark that expression can panic to insert jump to cleanup. + */ + void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, + bool can_panic = false) + { + if (expr_return_place != INVALID_PLACE) { - auto result = translated; - translated = INVALID_PLACE; - return result; + push_assignment (expr_return_place, expr); } - else if (expr_return_expr != nullptr) + else { - // Only allocate temporary, if needed. - push_tmp_assignment (expr_return_expr, lookup_type (expr)); - expr_return_expr = nullptr; - return translated; + push_tmp_assignment (expr, ty); } - else + + if (can_panic) { - return ctx.place_db.get_constant (lookup_type (expr)); + start_new_consecutive_bb (); } } - void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, - bool can_panic = false) + /** Mark place to be a result of processed subexpression. */ + void return_place (PlaceId place) { - rust_assert (expr_return_expr == nullptr); - if (can_panic) + if (expr_return_place != INVALID_PLACE) { - push_tmp_assignment (expr, ty); - // TODO, cleanup? - start_new_subsequent_bb (); + // Return place is already allocated, no need to defer assignment. + push_assignment (expr_return_place, place); } else { - translated = INVALID_PLACE; - expr_return_expr = expr; + translated = place; } } - void return_place (PlaceId place) + /** Explicitly return a unit value. Expression produces no value. */ + void return_unit (HIR::Expr &expr) { - expr_return_expr = nullptr; - translated = place; + translated = ctx.place_db.get_constant (lookup_type (expr)); } - void return_unit (HIR::Expr &expr) + PlaceId take_or_create_return_place (TyTy::BaseType *type) { - expr_return_expr = nullptr; - translated = ctx.place_db.get_constant (lookup_type (expr)); + auto result = (expr_return_place != INVALID_PLACE) + ? expr_return_place + : ctx.place_db.add_temporary (type); + expr_return_place = INVALID_PLACE; + return result; } }; +/** + * Helper to convert a pointer to an optional. Maps nullptr to nullopt. + * Optionals are mainly used here to provide monadic operations (map) over + * possibly null pointers. + */ +template +tl::optional +optional_from_ptr (T ptr) +{ + if (ptr != nullptr) + return {ptr}; + else + return tl::nullopt; +} + } // namespace BIR } // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index eb6a5efc1cfe..440549eba29b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -30,29 +30,28 @@ namespace BIR { * Special builder is needed to store short-circuiting context for directly * nested lazy boolean expressions. */ -class LazyBooleanExprBuilder : public AbstractBuilder, - public HIR::HIRExpressionVisitor +class LazyBooleanExprBuilder : public AbstractExprBuilder { BasicBlockId short_circuit_bb; public: - explicit LazyBooleanExprBuilder (BuilderContext &ctx) - : AbstractBuilder (ctx), short_circuit_bb (0) + explicit LazyBooleanExprBuilder (BuilderContext &ctx, + PlaceId expr_return_place = INVALID_PLACE) + : AbstractExprBuilder (ctx, expr_return_place), short_circuit_bb (0) {} PlaceId build (HIR::LazyBooleanExpr &expr) { - PlaceId return_place = ctx.place_db.add_temporary (lookup_type (expr)); + PlaceId return_place = take_or_create_return_place (lookup_type (expr)); short_circuit_bb = new_bb (); - visit (expr); - push_assignment (return_place, translated); + push_assignment (return_place, visit_expr (expr)); auto final_bb = new_bb (); push_goto (final_bb); ctx.current_bb = short_circuit_bb; - translated = ctx.place_db.get_constant (lookup_type (expr)); - push_assignment (return_place, translated); + push_assignment (return_place, + ctx.place_db.get_constant (lookup_type (expr))); push_goto (final_bb); ctx.current_bb = final_bb; @@ -62,11 +61,11 @@ class LazyBooleanExprBuilder : public AbstractBuilder, protected: void visit (HIR::LazyBooleanExpr &expr) override { - expr.get_lhs ()->accept_vis (*this); - push_switch (translated, {short_circuit_bb}); + auto lhs = visit_expr (*expr.get_lhs ()); + push_switch (make_arg (lhs), {short_circuit_bb}); - start_new_subsequent_bb (); - expr.get_rhs ()->accept_vis (*this); + start_new_consecutive_bb (); + return_place (visit_expr (*expr.get_rhs ())); } void visit (HIR::GroupedExpr &expr) override { @@ -77,15 +76,15 @@ class LazyBooleanExprBuilder : public AbstractBuilder, public: void visit (HIR::QualifiedPathInExpression &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::PathInExpression &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ClosureExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::StructExprStructFields &fields) override { @@ -97,119 +96,119 @@ class LazyBooleanExprBuilder : public AbstractBuilder, } void visit (HIR::LiteralExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::BorrowExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::DereferenceExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ErrorPropagationExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::NegationExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ArithmeticOrLogicalExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ComparisonExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::TypeCastExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::AssignmentExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::CompoundAssignmentExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ArrayExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::ArrayIndexExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::TupleExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::TupleIndexExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::CallExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::MethodCallExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::FieldAccessExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::BlockExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::UnsafeBlockExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::LoopExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::WhileLoopExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::WhileLetLoopExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::IfExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::IfExprConseqElse &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::IfLetExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::IfLetExprConseqElse &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::MatchExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::AwaitExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } void visit (HIR::AsyncBlockExpr &expr) override { - translated = ExprStmtBuilder (ctx).build (expr); + return_place (ExprStmtBuilder (ctx).build (expr)); } protected: // Illegal at this position. diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h index 0b4c83eca844..0596264afc51 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h @@ -23,16 +23,20 @@ namespace Rust { namespace BIR { -// Compiles binding of values into newly created variables. -// Used in let, match arm, and function parameter patterns. + +/** + * Compiles binding of values into newly created variables. + * Used in let, match arm, and function parameter patterns. + */ class PatternBindingBuilder : protected AbstractBuilder, public HIR::HIRPatternVisitor { + /** Value of initialization expression. */ PlaceId init; - // This is where lifetime annotations are stored. + /** This is where lifetime annotations are stored. */ tl::optional type; - // Emulates recursive stack saving and restoring inside a visitor. + /** Emulates recursive stack saving and restoring inside a visitor. */ class SavedState { PatternBindingBuilder *builder; @@ -55,21 +59,26 @@ class PatternBindingBuilder : protected AbstractBuilder, public: PatternBindingBuilder (BuilderContext &ctx, PlaceId init, HIR::Type *type) - : AbstractBuilder (ctx), init (init), - type (type ? tl::optional (type) : tl::nullopt) + : AbstractBuilder (ctx), init (init), type (optional_from_ptr (type)) {} void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); } - void visit_identifier (const Analysis::NodeMapping &node, bool is_ref) + void visit_identifier (const Analysis::NodeMapping &node, bool is_ref, + bool is_mut = false) { - translated = declare_variable (node); if (is_ref) { + translated = declare_variable ( + node, new TyTy::ReferenceType (node.get_hirid (), + TyTy::TyVar (node.get_hirid ()), + (is_mut) ? Mutability::Mut + : Mutability::Imm)); push_assignment (translated, new BorrowExpr (init)); } else { + translated = declare_variable (node); push_assignment (translated, init); } auto &init_place = ctx.place_db[init]; @@ -87,8 +96,10 @@ class PatternBindingBuilder : protected AbstractBuilder, { // Top-level identifiers are resolved directly to avoid useless temporary // (for cleaner BIR). - visit_identifier (pattern.get_mappings (), pattern.get_is_ref ()); + visit_identifier (pattern.get_mappings (), pattern.get_is_ref (), + pattern.is_mut ()); } + void visit (HIR::ReferencePattern &pattern) override { SavedState saved (this); @@ -104,6 +115,7 @@ class PatternBindingBuilder : protected AbstractBuilder, = 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); @@ -119,11 +131,13 @@ class PatternBindingBuilder : protected AbstractBuilder, 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); @@ -181,12 +195,14 @@ class PatternBindingBuilder : protected AbstractBuilder, field_ty->get_field_type (), saved.init, field_index); visit_identifier (ident_field->get_mappings (), - ident_field->get_has_ref ()); + ident_field->get_has_ref (), + ident_field->is_mut ()); break; } } } } + void visit_tuple_fields (std::vector> &fields, SavedState &saved, size_t &index) { diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index fa2f5965af68..7df54a4880aa 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -29,6 +29,7 @@ namespace BIR { class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor { TyTy::VariantDef *struct_ty; + /** Output of the builder. */ std::vector init_values; public: @@ -47,34 +48,33 @@ class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor void visit (HIR::StructExprFieldIdentifier &field) override { - resolve_variable (field, translated); - handle_named_field (field); + handle_named_field (field, resolve_variable (field)); } void visit (HIR::StructExprFieldIdentifierValue &field) override { - translated = ExprStmtBuilder (ctx).build (*field.get_value ()); - handle_named_field (field); + auto value = ExprStmtBuilder (ctx).build (*field.get_value ()); + handle_named_field (field, value); } void visit (HIR::StructExprFieldIndexValue &field) override { - translated = ExprStmtBuilder (ctx).build (*field.get_value ()); - coercion_site (translated, + auto value = ExprStmtBuilder (ctx).build (*field.get_value ()); + coercion_site (value, struct_ty->get_field_at_index (field.get_tuple_index ()) ->get_field_type ()); - init_values.push_back (translated); + init_values.push_back (value); } private: - template void handle_named_field (T &field) + template void handle_named_field (T &field, PlaceId value) { 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); + rust_assert (value != INVALID_PLACE); + coercion_site (value, field_type->get_field_type ()); + init_values.push_back (value); } protected: diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h index 322d00d280e5..177b65558899 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h @@ -74,12 +74,18 @@ class Builder : public AbstractBuilder void handle_body (HIR::BlockExpr &body) { translated = ExprStmtBuilder (ctx).build (body); - if (body.has_expr ()) + if (body.has_expr () && !lookup_type (body)->is_unit ()) { push_assignment (RETURN_VALUE_PLACE, translated); ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN); } - } + else if (!ctx.get_current_bb ().is_terminated ()) + { + push_assignment (RETURN_VALUE_PLACE, + ctx.place_db.get_constant (lookup_type (body))); + ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN); + } + }; }; } // namespace BIR diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc index 66870ddeb565..23aa7c6b078b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc @@ -114,24 +114,27 @@ Dump::go (bool enable_simplify_cfg) stream << "fn " << name << "("; print_comma_separated (stream, func.arguments, [this] (PlaceId place_id) { stream << "_" << place_map[place_id] << ": " - << get_tyty_name (place_db[place_id].tyty); + << get_tyty_name (func.place_db[place_id].tyty); }); - stream << ") -> " << get_tyty_name (place_db[RETURN_VALUE_PLACE].tyty) + stream << ") -> " << get_tyty_name (func.place_db[RETURN_VALUE_PLACE].tyty) << " {\n"; - for (PlaceId id = FIRST_VARIABLE_PLACE; id < place_db.size (); ++id) + // Print locals declaration. + for (PlaceId id = FIRST_VARIABLE_PLACE; id < func.place_db.size (); ++id) { - const Place &place = place_db[id]; + const Place &place = func.place_db[id]; if (place.kind == Place::VARIABLE || place.kind == Place::TEMPORARY) { if (std::find (func.arguments.begin (), func.arguments.end (), id) != func.arguments.end ()) continue; - stream << indentation << "let _" << place_map[id] << ": " - << get_tyty_name (place_db[id].tyty) << ";\n"; + stream << indentation << "let _"; + stream << place_map[id] << ": " + << get_tyty_name (func.place_db[id].tyty) << ";\n"; } } + // Print BBs. for (node_bb = 0; node_bb < func.basic_blocks.size (); ++node_bb) { if (bb_fold_map[node_bb] != node_bb) @@ -141,6 +144,8 @@ Dump::go (bool enable_simplify_cfg) && func.basic_blocks[node_bb].successors.empty ()) continue; + bb_terminated = false; + BasicBlock &bb = func.basic_blocks[node_bb]; stream << "\n"; stream << indentation << "bb" << bb_fold_map[node_bb] << ": {\n"; @@ -150,10 +155,15 @@ Dump::go (bool enable_simplify_cfg) visit (stmt); stream << ";\n"; } + if (!bb_terminated) + { + stream << indentation << indentation << "goto -> bb" + << bb_fold_map[bb.successors.at (0)] << ";\n"; + } stream << indentation << "}\n"; } - stream << "}\n\n"; + stream << "}\n"; } void Dump::visit (Node &node) @@ -162,7 +172,8 @@ Dump::visit (Node &node) switch (node.get_kind ()) { case Node::Kind::ASSIGNMENT: { - stream << "_" << place_map[node.get_place ()] << " = "; + visit_place (node.get_place ()); + stream << " = "; node.get_expr ().accept_vis (*this); break; } @@ -175,13 +186,16 @@ Dump::visit (Node &node) stream << "bb" << bb_fold_map[succ]; }); stream << "]"; + bb_terminated = true; break; case Node::Kind::RETURN: stream << "return"; + bb_terminated = true; break; case Node::Kind::GOTO: stream << "goto -> bb" << bb_fold_map[func.basic_blocks[node_bb].successors.at (0)]; + bb_terminated = true; break; case Node::Kind::STORAGE_DEAD: stream << "StorageDead("; @@ -200,7 +214,7 @@ Dump::visit (Node &node) void Dump::visit_place (PlaceId place_id) { - const Place &place = place_db[place_id]; + const Place &place = func.place_db[place_id]; switch (place.kind) { case Place::TEMPORARY: @@ -237,8 +251,8 @@ Dump::visit_place (PlaceId place_id) void Dump::visit_move_place (PlaceId place_id) { - const Place &place = place_db[place_id]; - if (!place.is_copy) + const Place &place = func.place_db[place_id]; + if (place.is_rvalue || !place.is_copy) stream << "move "; visit_place (place_id); } @@ -254,7 +268,7 @@ Dump::visit (BorrowExpr &expr) void Dump::visit_lifetime (PlaceId place_id) { - const Place &place = place_db[place_id]; + const Place &place = func.place_db[place_id]; if (place.lifetime.has_lifetime ()) { if (place.lifetime.id == STATIC_LIFETIME_ID) @@ -279,7 +293,7 @@ Dump::visit (CallExpr &expr) { stream << "Call("; if (auto fn_type - = place_db[expr.get_callable ()].tyty->try_as ()) + = func.place_db[expr.get_callable ()].tyty->try_as ()) { stream << fn_type->get_identifier (); } @@ -288,18 +302,17 @@ Dump::visit (CallExpr &expr) visit_move_place (expr.get_callable ()); } stream << ")("; - for (auto &place : expr.get_arguments ()) - { - visit_move_place (place); - stream << ", "; - } + print_comma_separated (stream, expr.get_arguments (), + [this] (PlaceId place_id) { + visit_move_place (place_id); + }); stream << ") -> ["; - print_comma_separated (stream, - func.basic_blocks[bb_fold_map[node_bb]].successors, - [this] (const BasicBlockId &dst) { - stream << "bb" << bb_fold_map[dst]; + print_comma_separated (stream, func.basic_blocks[node_bb].successors, + [this] (BasicBlockId succ) { + stream << "bb" << bb_fold_map[succ]; }); stream << "]"; + bb_terminated = true; } void diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h index edf7d1ea1ec3..1efc0ea2bf46 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h @@ -28,10 +28,10 @@ namespace Rust { namespace BIR { +/** Prints the BIR to a stream in a format resembling rustc's MIR. */ class Dump : public Visitor { std::ostream &stream; - const PlaceDB &place_db; Function &func; const std::string &name; @@ -40,10 +40,11 @@ class Dump : public Visitor PlaceId node_place = INVALID_PLACE; BasicBlockId node_bb = INVALID_BB; + bool bb_terminated = false; public: Dump (std::ostream &os, Function &func, const std::string &name) - : stream (os), place_db (func.place_db), func (func), name (name), + : stream (os), func (func), name (name), bb_fold_map (func.basic_blocks.size ()), place_map (func.place_db.size ()) {} void go (bool enable_simplify_cfg = false); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index ce32f9262ceb..66b131dee1a7 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -148,30 +148,9 @@ class PlaceDB 0); } - PlaceId lookup_variable (NodeId id) - { - PlaceId current = FIRST_VARIABLE_PLACE; - - while (current != places.size ()) - { - if (places[current].kind == Place::VARIABLE - && places[current].variable_or_field_index == id) - return current; - current++; - } - return INVALID_PLACE; - }; - - PlaceId add_temporary (TyTy::BaseType *tyty) - { - return add_place ( - {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}, - 0); - } - - WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind, - TyTy::BaseType *tyty, - PlaceId parent, size_t id = 0) + [[nodiscard]] PlaceId lookup_or_add_path (Place::Kind kind, + TyTy::BaseType *tyty, + PlaceId parent, size_t id = 0) { PlaceId current = 0; if (parent < places.size ()) @@ -193,6 +172,13 @@ class PlaceDB current); } + PlaceId add_temporary (TyTy::BaseType *tyty) + { + return add_place ( + {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}, + 0); + } + PlaceId get_constant (TyTy::BaseType *tyty) { auto lookup = constants_lookup.find (tyty); @@ -206,6 +192,44 @@ class PlaceDB return places.size () - 1; } + PlaceId lookup_variable (NodeId id) + { + PlaceId current = FIRST_VARIABLE_PLACE; + + while (current != places.size ()) + { + if (places[current].kind == Place::VARIABLE + && places[current].variable_or_field_index == id) + return current; + current++; + } + return INVALID_PLACE; + }; + + PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty) + { + auto lookup = lookup_variable (id); + if (lookup != INVALID_PLACE) + return lookup; + places.push_back ( + {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}); + return places.size () - 1; + }; + + PlaceId into_rvalue (PlaceId place) + { + if (places[place].is_rvalue || places[place].kind == Place::CONSTANT + || places[place].tyty->get_kind () == TyTy::REF) + return place; + return add_place ({Place::TEMPORARY, + 0, + {}, + places[place].is_copy, + true, + NO_LIFETIME, + places[place].tyty}); + } + private: static bool is_type_copy (TyTy::BaseType *ty) {