| // 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/>. |
| |
| #include "rust-compile-block.h" |
| #include "rust-compile-stmt.h" |
| #include "rust-compile-expr.h" |
| |
| namespace Rust { |
| namespace Compile { |
| |
| CompileBlock::CompileBlock (Context *ctx, Bvariable *result) |
| : HIRCompileBase (ctx), translated (nullptr), result (result) |
| {} |
| |
| tree |
| CompileBlock::compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result) |
| { |
| CompileBlock compiler (ctx, result); |
| compiler.visit (*expr); |
| return compiler.translated; |
| } |
| |
| void |
| CompileBlock::visit (HIR::BlockExpr &expr) |
| { |
| fncontext fnctx = ctx->peek_fn (); |
| tree fndecl = fnctx.fndecl; |
| Location start_location = expr.get_locus (); |
| Location end_location = expr.get_end_locus (); |
| auto body_mappings = expr.get_mappings (); |
| |
| Resolver::Rib *rib = nullptr; |
| if (!ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib)) |
| { |
| rust_fatal_error (expr.get_locus (), "failed to setup locals per block"); |
| return; |
| } |
| |
| std::vector<Bvariable *> locals |
| = compile_locals_for_block (ctx, *rib, fndecl); |
| |
| tree enclosing_scope = ctx->peek_enclosing_scope (); |
| tree new_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals, |
| start_location, end_location); |
| ctx->push_block (new_block); |
| |
| for (auto &s : expr.get_statements ()) |
| { |
| auto compiled_expr = CompileStmt::Compile (s.get (), ctx); |
| if (compiled_expr != nullptr) |
| { |
| tree s = convert_to_void (compiled_expr, ICV_STATEMENT); |
| ctx->add_statement (s); |
| } |
| } |
| |
| if (expr.has_expr ()) |
| { |
| // the previous passes will ensure this is a valid return or |
| // a valid trailing expression |
| tree compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx); |
| if (compiled_expr != nullptr) |
| { |
| if (result == nullptr) |
| { |
| ctx->add_statement (compiled_expr); |
| } |
| else |
| { |
| tree result_reference = ctx->get_backend ()->var_expression ( |
| result, expr.get_final_expr ()->get_locus ()); |
| |
| tree assignment |
| = ctx->get_backend ()->assignment_statement (result_reference, |
| compiled_expr, |
| expr.get_locus ()); |
| ctx->add_statement (assignment); |
| } |
| } |
| } |
| |
| ctx->pop_block (); |
| translated = new_block; |
| } |
| |
| void |
| CompileConditionalBlocks::visit (HIR::IfExpr &expr) |
| { |
| fncontext fnctx = ctx->peek_fn (); |
| tree fndecl = fnctx.fndecl; |
| tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); |
| tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); |
| |
| translated |
| = ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block, |
| NULL, expr.get_locus ()); |
| } |
| |
| void |
| CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) |
| { |
| fncontext fnctx = ctx->peek_fn (); |
| tree fndecl = fnctx.fndecl; |
| tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); |
| tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); |
| tree else_block = CompileBlock::compile (expr.get_else_block (), ctx, result); |
| |
| translated |
| = ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block, |
| else_block, expr.get_locus ()); |
| } |
| |
| void |
| CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) |
| { |
| fncontext fnctx = ctx->peek_fn (); |
| tree fndecl = fnctx.fndecl; |
| tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); |
| tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); |
| |
| // else block |
| std::vector<Bvariable *> locals; |
| Location start_location = expr.get_conseq_if_expr ()->get_locus (); |
| Location end_location = expr.get_conseq_if_expr ()->get_locus (); // FIXME |
| tree enclosing_scope = ctx->peek_enclosing_scope (); |
| tree else_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals, |
| start_location, end_location); |
| ctx->push_block (else_block); |
| |
| tree else_stmt_decl |
| = CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), ctx, |
| result); |
| ctx->add_statement (else_stmt_decl); |
| |
| ctx->pop_block (); |
| |
| translated |
| = ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block, |
| else_block, expr.get_locus ()); |
| } |
| |
| } // namespace Compile |
| } // namespace Rust |