// 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 // . #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 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 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