diff options
Diffstat (limited to 'gcc/rust/backend/rust-compile-block.cc')
-rw-r--r-- | gcc/rust/backend/rust-compile-block.cc | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/rust-compile-block.cc new file mode 100644 index 0000000..99674e2 --- /dev/null +++ b/gcc/rust/backend/rust-compile-block.cc @@ -0,0 +1,158 @@ +// 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-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 |