diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 53 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-block.h | 2 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-expr.h | 5 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower.cc | 27 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-expr.h | 2 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 30 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 40 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check.h | 6 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/compilable/loop6.rs | 11 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/fail_compilation/break2.rs | 14 |
10 files changed, 183 insertions, 7 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 7b25c5e..1ca7631 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -641,11 +641,61 @@ public: } } + void visit (HIR::WhileLoopExpr &expr) + { + fncontext fnctx = ctx->peek_fn (); + if (expr.has_loop_label ()) + { + HIR::LoopLabel &loop_label = expr.get_loop_label (); + Blabel *label + = ctx->get_backend ()->label (fnctx.fndecl, + loop_label.get_lifetime ().get_name (), + loop_label.get_locus ()); + Bstatement *label_decl + = ctx->get_backend ()->label_definition_statement (label); + ctx->add_statement (label_decl); + ctx->insert_label_decl ( + loop_label.get_lifetime ().get_mappings ().get_hirid (), label); + } + + std::vector<Bvariable *> locals; + Location start_location = expr.get_loop_block ()->get_locus (); + Location end_location = expr.get_loop_block ()->get_locus (); // FIXME + + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Bblock *loop_block + = ctx->get_backend ()->block (fnctx.fndecl, enclosing_scope, locals, + start_location, end_location); + ctx->push_block (loop_block); + + Bexpression *condition + = CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx); + Bexpression *exit_expr + = ctx->get_backend ()->exit_expression (condition, expr.get_locus ()); + Bstatement *break_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr); + ctx->add_statement (break_stmt); + + Bblock *code_block + = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr); + Bstatement *code_block_stmt + = ctx->get_backend ()->block_statement (code_block); + ctx->add_statement (code_block_stmt); + + ctx->pop_block (); + + Bexpression *loop_expr + = ctx->get_backend ()->loop_expression (loop_block, expr.get_locus ()); + Bstatement *loop_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr); + ctx->add_statement (loop_stmt); + } + void visit (HIR::BreakExpr &expr) { + fncontext fnctx = ctx->peek_fn (); if (expr.has_break_expr ()) { - fncontext fnctx = ctx->peek_fn (); Bexpression *compiled_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); @@ -695,7 +745,6 @@ public: } else { - fncontext fnctx = ctx->peek_fn (); Bexpression *exit_expr = ctx->get_backend ()->exit_expression ( ctx->get_backend ()->boolean_constant_expression (true), expr.get_locus ()); diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index c945042..ec0f895 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -155,6 +155,8 @@ public: std::move (outer_attribs)); } + void visit (AST::WhileLoopExpr &expr); + private: ASTLoweringExprWithBlock () : ASTLoweringBase (), translated (nullptr), terminated (false) diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index e10448f..8e80c7a 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -700,6 +700,11 @@ public: translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); } + void visit (AST::WhileLoopExpr &expr) + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + void visit (AST::BreakExpr &expr) { std::vector<HIR::Attribute> outer_attribs; diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index c1ea01a..230919a 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -242,5 +242,32 @@ ASTLowerStructExprField::visit (AST::StructExprFieldIdentifier &field) field.get_locus ()); } +// rust-ast-lower-block.h + +void +ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) +{ + std::vector<HIR::Attribute> outer_attribs; + HIR::BlockExpr *loop_block + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated); + + HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + HIR::Expr *loop_condition + = ASTLoweringExpr::translate (expr.get_predicate_expr ().get (), + &terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::WhileLoopExpr (mapping, + std::unique_ptr<HIR::Expr> (loop_condition), + std::unique_ptr<HIR::BlockExpr> (loop_block), + expr.get_locus (), std::move (loop_label), + std::move (outer_attribs)); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index e92e059..3fd2ebc 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -3419,6 +3419,8 @@ public: void accept_vis (HIRVisitor &vis) override; + std::unique_ptr<Expr> &get_predicate_expr () { return condition; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 9cfa04d..38a878c 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -297,6 +297,36 @@ public: ResolveExpr::go (expr.get_break_expr ().get (), expr.get_node_id ()); } + void visit (AST::WhileLoopExpr &expr) + { + if (expr.has_loop_label ()) + { + auto label = expr.get_loop_label (); + if (label.get_lifetime ().get_lifetime_type () + != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + auto label_name = label.get_lifetime ().get_lifetime_name (); + auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); + resolver->get_label_scope ().insert ( + label_name, label_lifetime_node_id, label.get_locus (), false, + [&] (std::string, NodeId, Location locus) -> void { + rust_error_at (label.get_locus (), + "label redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + resolver->insert_new_definition (label_lifetime_node_id, + Definition{label_lifetime_node_id, + label.get_node_id ()}); + } + ResolveExpr::go (expr.get_predicate_expr ().get (), expr.get_node_id ()); + ResolveExpr::go (expr.get_loop_block ().get (), expr.get_node_id ()); + } + private: ResolveExpr (NodeId parent) : ResolverBase (parent) {} }; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 87aeae6..7062f54 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -670,10 +670,6 @@ public: void visit (HIR::GroupedExpr &expr) { - printf ("inside grouped expr: \n%s\n inside it is: \n%s\n", - expr.as_string ().c_str (), - expr.get_expr_in_parens ()->as_string ().c_str ()); - infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get (), false); } @@ -758,7 +754,15 @@ public: void visit (HIR::LoopExpr &expr) { context->push_new_loop_context (expr.get_mappings ().get_hirid ()); - TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + TyTy::TyBase *block_expr + = TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + if (block_expr->get_kind () != TyTy::TypeKind::UNIT) + { + rust_error_at (expr.get_loop_block ()->get_locus_slow (), + "expected () got %s", block_expr->as_string ().c_str ()); + return; + } + TyTy::TyBase *loop_context_type = context->pop_loop_context (); bool loop_context_type_infered @@ -772,6 +776,25 @@ public: : new TyTy::UnitType (expr.get_mappings ().get_hirid ()); } + void visit (HIR::WhileLoopExpr &expr) + { + context->push_new_while_loop_context (expr.get_mappings ().get_hirid ()); + + TypeCheckExpr::Resolve (expr.get_predicate_expr ().get (), false); + TyTy::TyBase *block_expr + = TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + + if (block_expr->get_kind () != TyTy::TypeKind::UNIT) + { + rust_error_at (expr.get_loop_block ()->get_locus_slow (), + "expected () got %s", block_expr->as_string ().c_str ()); + return; + } + + context->pop_loop_context (); + infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + } + void visit (HIR::BreakExpr &expr) { if (!inside_loop) @@ -786,6 +809,13 @@ public: = TypeCheckExpr::Resolve (expr.get_expr ().get (), false); TyTy::TyBase *loop_context = context->peek_loop_context (); + if (loop_context->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (expr.get_locus (), + "can only break with a value inside `loop`"); + return; + } + TyTy::TyBase *combined = loop_context->combine (break_expr_tyty); context->swap_head_loop_context (combined); } diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 531d241..aa11b7e 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -63,6 +63,12 @@ public: loop_type_stack.push_back (infer_var); } + void push_new_while_loop_context (HirId id) + { + TyTy::TyBase *infer_var = new TyTy::ErrorType (id); + loop_type_stack.push_back (infer_var); + } + TyTy::TyBase *peek_loop_context () { return loop_type_stack.back (); } TyTy::TyBase *pop_loop_context () diff --git a/gcc/testsuite/rust.test/compilable/loop6.rs b/gcc/testsuite/rust.test/compilable/loop6.rs new file mode 100644 index 0000000..ecd3ad4 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop6.rs @@ -0,0 +1,11 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let mut c; + while b > 10 { + c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust.test/fail_compilation/break2.rs b/gcc/testsuite/rust.test/fail_compilation/break2.rs new file mode 100644 index 0000000..53cee9a --- /dev/null +++ b/gcc/testsuite/rust.test/fail_compilation/break2.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let mut c; + while b > 10 { + if (b == 2) { + break b; + } + c = a + b; + a = b; + b = c; + } +} |