diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index dde833fe7fdf..eb56b657983c 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -2828,7 +2828,7 @@ class BlockExpr : public ExprWithBlock std::vector outer_attrs; std::vector inner_attrs; std::vector > statements; - std::unique_ptr expr; + std::unique_ptr expr; Location locus; bool marked_for_strip = false; @@ -2842,7 +2842,7 @@ class BlockExpr : public ExprWithBlock bool has_tail_expr () const { return expr != nullptr; } BlockExpr (std::vector > block_statements, - std::unique_ptr block_expr, + std::unique_ptr block_expr, std::vector inner_attribs, std::vector outer_attribs, Location locus) : outer_attrs (std::move (outer_attribs)), @@ -2859,7 +2859,7 @@ class BlockExpr : public ExprWithBlock { // guard to protect from null pointer dereference if (other.expr != nullptr) - expr = other.expr->clone_expr_without_block (); + expr = other.expr->clone_expr (); statements.reserve (other.statements.size ()); for (const auto &e : other.statements) @@ -2877,7 +2877,7 @@ class BlockExpr : public ExprWithBlock // guard to protect from null pointer dereference if (other.expr != nullptr) - expr = other.expr->clone_expr_without_block (); + expr = other.expr->clone_expr (); else expr = nullptr; @@ -2929,7 +2929,7 @@ class BlockExpr : public ExprWithBlock std::vector > &get_statements () { return statements; } // TODO: is this better? Or is a "vis_block" better? - std::unique_ptr &get_tail_expr () + std::unique_ptr &get_tail_expr () { rust_assert (has_tail_expr ()); return expr; diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h index c840112da11a..72946774a1f3 100644 --- a/gcc/rust/ast/rust-stmt.h +++ b/gcc/rust/ast/rust-stmt.h @@ -269,14 +269,17 @@ class ExprStmtWithoutBlock : public ExprStmt class ExprStmtWithBlock : public ExprStmt { std::unique_ptr expr; + bool semicolon_followed; public: std::string as_string () const override; std::vector locals; - ExprStmtWithBlock (std::unique_ptr expr, Location locus) - : ExprStmt (locus), expr (std::move (expr)) + ExprStmtWithBlock (std::unique_ptr expr, Location locus, + bool semicolon_followed) + : ExprStmt (locus), expr (std::move (expr)), + semicolon_followed (semicolon_followed) {} // Copy constructor with clone @@ -318,6 +321,8 @@ class ExprStmtWithBlock : public ExprStmt return expr; } + bool is_semicolon_followed () const { return semicolon_followed; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index 128a729dd875..e3f8a36748a3 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -54,10 +54,12 @@ class CompileConditionalBlocks : public HIRCompileBase public: static Bstatement *compile (HIR::IfExpr *expr, Context *ctx, - Bvariable *result) + Bvariable *result, bool *terminated) { CompileConditionalBlocks resolver (ctx, result); expr->accept_vis (resolver); + if (terminated) + *terminated = resolver.terminated; return resolver.translated; } @@ -69,9 +71,11 @@ class CompileConditionalBlocks : public HIRCompileBase private: CompileConditionalBlocks (Context *ctx, Bvariable *result) - : HIRCompileBase (ctx), translated (nullptr), result (result) + : HIRCompileBase (ctx), translated (nullptr), result (result), + terminated (false) {} + bool terminated; Bstatement *translated; Bvariable *result; }; @@ -91,17 +95,20 @@ class CompileExprWithBlock : public HIRCompileBase void visit (HIR::IfExpr &expr) override { - translated = CompileConditionalBlocks::compile (&expr, ctx, result); + translated + = CompileConditionalBlocks::compile (&expr, ctx, result, nullptr); } void visit (HIR::IfExprConseqElse &expr) override { - translated = CompileConditionalBlocks::compile (&expr, ctx, result); + translated + = CompileConditionalBlocks::compile (&expr, ctx, result, nullptr); } void visit (HIR::IfExprConseqIf &expr) override { - translated = CompileConditionalBlocks::compile (&expr, ctx, result); + translated + = CompileConditionalBlocks::compile (&expr, ctx, result, nullptr); } private: diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 886657568ae7..2024a6f91124 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -503,6 +503,11 @@ class TyTyResolveCompile : public TyTy::TyVisitor translated = compiled_type; } + void visit (TyTy::NeverType &) override + { + translated = ctx->get_backend ()->void_type (); + } + private: TyTyResolveCompile (Context *ctx) : ctx (ctx), translated (nullptr) {} diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index f98ebc66ad4f..1874b913201c 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -33,10 +33,12 @@ class CompileExpr : public HIRCompileBase using Rust::Compile::HIRCompileBase::visit; public: - static Bexpression *Compile (HIR::Expr *expr, Context *ctx) + static Bexpression *Compile (HIR::Expr *expr, Context *ctx, bool *terminated) { CompileExpr compiler (ctx); expr->accept_vis (compiler); + if (terminated) + *terminated = compiler.terminated; return compiler.translated; } @@ -45,7 +47,11 @@ class CompileExpr : public HIRCompileBase HIR::Expr *tuple_expr = expr.get_tuple_expr ().get (); TupleIndex index = expr.get_tuple_index (); - Bexpression *receiver_ref = CompileExpr::Compile (tuple_expr, ctx); + Bexpression *receiver_ref + = CompileExpr::Compile (tuple_expr, ctx, &terminated); + if (terminated) + return; + translated = ctx->get_backend ()->struct_field_expression (receiver_ref, index, expr.get_locus ()); @@ -75,7 +81,9 @@ class CompileExpr : public HIRCompileBase std::vector vals; for (auto &elem : expr.get_tuple_elems ()) { - auto e = CompileExpr::Compile (elem.get (), ctx); + auto e = CompileExpr::Compile (elem.get (), ctx, &terminated); + if (terminated) + return; vals.push_back (e); } @@ -92,15 +100,19 @@ class CompileExpr : public HIRCompileBase if (expr.has_return_expr ()) { Bexpression *compiled_expr - = CompileExpr::Compile (expr.return_expr.get (), ctx); - rust_assert (compiled_expr != nullptr); + = CompileExpr::Compile (expr.return_expr.get (), ctx, &terminated); + if (terminated) + return; + rust_assert (compiled_expr != nullptr); retstmts.push_back (compiled_expr); } auto s = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts, expr.get_locus ()); ctx->add_statement (s); + + terminated = true; } void visit (HIR::CallExpr &expr) override; @@ -246,8 +258,12 @@ class CompileExpr : public HIRCompileBase void visit (HIR::AssignmentExpr &expr) override { fncontext fn = ctx->peek_fn (); - auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx, &terminated); + if (terminated) + return; + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx, &terminated); + if (terminated) + return; Bstatement *assignment = ctx->get_backend ()->assignment_statement (fn.fndecl, lhs, rhs, @@ -257,8 +273,15 @@ class CompileExpr : public HIRCompileBase void visit (HIR::ArrayIndexExpr &expr) override { - Bexpression *array = CompileExpr::Compile (expr.get_array_expr (), ctx); - Bexpression *index = CompileExpr::Compile (expr.get_index_expr (), ctx); + Bexpression *array + = CompileExpr::Compile (expr.get_array_expr (), ctx, &terminated); + if (terminated) + return; + Bexpression *index + = CompileExpr::Compile (expr.get_index_expr (), ctx, &terminated); + if (terminated) + return; + translated = ctx->get_backend ()->array_index_expression (array, index, expr.get_locus ()); @@ -278,6 +301,9 @@ class CompileExpr : public HIRCompileBase Btype *array_type = TyTyResolveCompile::compile (ctx, tyty); expr.get_internal_elements ()->accept_vis (*this); + if (terminated) + return; + std::vector indexes; for (size_t i = 0; i < constructor.size (); i++) indexes.push_back (i); @@ -291,16 +317,18 @@ class CompileExpr : public HIRCompileBase void visit (HIR::ArrayElemsValues &elems) override { elems.iterate ([&] (HIR::Expr *e) mutable -> bool { - Bexpression *translated_expr = CompileExpr::Compile (e, ctx); + Bexpression *translated_expr = CompileExpr::Compile (e, ctx, &terminated); constructor.push_back (translated_expr); - return true; + return !terminated; }); } void visit (HIR::ArrayElemsCopied &elems) override { Bexpression *translated_expr - = CompileExpr::Compile (elems.get_elem_to_copy (), ctx); + = CompileExpr::Compile (elems.get_elem_to_copy (), ctx, &terminated); + if (terminated) + return; for (size_t i = 0; i < elems.get_num_elements (); ++i) constructor.push_back (translated_expr); @@ -308,9 +336,14 @@ class CompileExpr : public HIRCompileBase void visit (HIR::ArithmeticOrLogicalExpr &expr) override { + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx, &terminated); + if (terminated) + return; + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx, &terminated); + if (terminated) + return; + auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); auto location = expr.get_locus (); translated @@ -320,9 +353,14 @@ class CompileExpr : public HIRCompileBase void visit (HIR::ComparisonExpr &expr) override { + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx, &terminated); + if (terminated) + return; + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx, &terminated); + if (terminated) + return; + auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); auto location = expr.get_locus (); translated @@ -331,9 +369,16 @@ class CompileExpr : public HIRCompileBase void visit (HIR::LazyBooleanExpr &expr) override { + // FIXME: This is NOT correct. + // Consider `func() || return -1;` or `func() || { bar(); false };`. + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx, &terminated); + if (terminated) + return; + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx, &terminated); + if (terminated) + return; + auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); auto location = expr.get_locus (); translated @@ -342,8 +387,12 @@ class CompileExpr : public HIRCompileBase void visit (HIR::NegationExpr &expr) override { + auto negated_expr + = CompileExpr::Compile (expr.get_expr (), ctx, &terminated); + if (terminated) + return; + auto op = expr.get_expr_type (); - auto negated_expr = CompileExpr::Compile (expr.get_expr (), ctx); auto location = expr.get_locus (); translated @@ -352,7 +401,10 @@ class CompileExpr : public HIRCompileBase void visit (HIR::IfExpr &expr) override { - auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr); + auto stmt + = CompileConditionalBlocks::compile (&expr, ctx, nullptr, &terminated); + if (terminated) + return; ctx->add_statement (stmt); } @@ -383,7 +435,10 @@ class CompileExpr : public HIRCompileBase ctx->add_statement (ret_var_stmt); } - auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); + auto stmt + = CompileConditionalBlocks::compile (&expr, ctx, tmp, &terminated); + if (terminated) + return; ctx->add_statement (stmt); if (tmp != NULL) @@ -420,7 +475,10 @@ class CompileExpr : public HIRCompileBase ctx->add_statement (ret_var_stmt); } - auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); + auto stmt + = CompileConditionalBlocks::compile (&expr, ctx, tmp, &terminated); + if (terminated) + return; ctx->add_statement (stmt); if (tmp != NULL) @@ -441,7 +499,7 @@ class CompileExpr : public HIRCompileBase } Bvariable *tmp = NULL; - bool needs_temp = !block_tyty->is_unit (); + bool needs_temp = !block_tyty->is_unit () && expr.is_tail_reachable (); if (needs_temp) { fncontext fnctx = ctx->peek_fn (); @@ -465,6 +523,8 @@ class CompileExpr : public HIRCompileBase translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); } + + terminated = !expr.is_tail_reachable (); } void visit (HIR::StructExprStructFields &struct_expr) override @@ -484,10 +544,13 @@ class CompileExpr : public HIRCompileBase // struct was specified those fields are filed via accesors std::vector vals; struct_expr.iterate ([&] (HIR::StructExprField *field) mutable -> bool { - Bexpression *expr = CompileStructExprField::Compile (field, ctx); + Bexpression *expr + = CompileStructExprField::Compile (field, ctx, &terminated); vals.push_back (expr); - return true; + return !terminated; }); + if (terminated) + return; translated = ctx->get_backend ()->constructor_expression (type, vals, @@ -496,7 +559,8 @@ class CompileExpr : public HIRCompileBase void visit (HIR::GroupedExpr &expr) override { - translated = CompileExpr::Compile (expr.get_expr_in_parens ().get (), ctx); + translated = CompileExpr::Compile (expr.get_expr_in_parens ().get (), ctx, + &terminated); } void visit (HIR::FieldAccessExpr &expr) override @@ -517,7 +581,10 @@ class CompileExpr : public HIRCompileBase adt->get_field (expr.get_field_name (), &index); Bexpression *struct_ref - = CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx, + &terminated); + if (terminated) + return; translated = ctx->get_backend ()->struct_field_expression (struct_ref, index, @@ -629,7 +696,10 @@ class CompileExpr : public HIRCompileBase ctx->push_loop_begin_label (loop_begin_label); Bexpression *condition - = CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx, + &terminated); + if (terminated) + return; Bexpression *exit_expr = ctx->get_backend ()->exit_expression (condition, expr.get_locus ()); Bstatement *break_stmt @@ -658,7 +728,9 @@ class CompileExpr : public HIRCompileBase if (expr.has_break_expr ()) { Bexpression *compiled_expr - = CompileExpr::Compile (expr.get_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_expr ().get (), ctx, &terminated); + if (terminated) + return; Bvariable *loop_result_holder = ctx->peek_loop_context (); Bexpression *result_reference = ctx->get_backend ()->var_expression ( @@ -713,6 +785,8 @@ class CompileExpr : public HIRCompileBase = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr); ctx->add_statement (break_stmt); } + + terminated = true; } void visit (HIR::ContinueExpr &expr) override @@ -752,12 +826,16 @@ class CompileExpr : public HIRCompileBase Bstatement *goto_label = ctx->get_backend ()->goto_statement (label, expr.get_locus ()); ctx->add_statement (goto_label); + + terminated = true; } void visit (HIR::BorrowExpr &expr) override { Bexpression *main_expr - = CompileExpr::Compile (expr.get_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_expr ().get (), ctx, &terminated); + if (terminated) + return; translated = ctx->get_backend ()->address_expression (main_expr, expr.get_locus ()); @@ -766,7 +844,9 @@ class CompileExpr : public HIRCompileBase void visit (HIR::DereferenceExpr &expr) override { Bexpression *main_expr - = CompileExpr::Compile (expr.get_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_expr ().get (), ctx, &terminated); + if (terminated) + return; TyTy::BaseType *tyty = nullptr; if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), @@ -786,10 +866,14 @@ class CompileExpr : public HIRCompileBase } private: - CompileExpr (Context *ctx) : HIRCompileBase (ctx), translated (nullptr) {} + CompileExpr (Context *ctx) + : HIRCompileBase (ctx), translated (nullptr), terminated (false) + {} Bexpression *translated; std::vector constructor; + + bool terminated; }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h index cee3a3ba5518..008a2912ed4a 100644 --- a/gcc/rust/backend/rust-compile-implitem.h +++ b/gcc/rust/backend/rust-compile-implitem.h @@ -50,8 +50,11 @@ class CompileInherentImplItem : public HIRCompileBase &resolved_type); rust_assert (ok); + bool terminated = false; ::Btype *type = TyTyResolveCompile::compile (ctx, resolved_type); - Bexpression *value = CompileExpr::Compile (constant.get_expr (), ctx); + Bexpression *value + = CompileExpr::Compile (constant.get_expr (), ctx, &terminated); + rust_assert (!terminated && value); std::string ident = self->get_name () + "_" + constant.get_identifier (); Bexpression *const_expr = ctx->get_backend ()->named_constant_expression ( diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index 2bbfe4cbee70..2627decc2cd8 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -50,7 +50,7 @@ class CompileItem : public HIRCompileBase rust_assert (ok); Btype *type = TyTyResolveCompile::compile (ctx, resolved_type); - Bexpression *value = CompileExpr::Compile (var.get_expr (), ctx); + Bexpression *value = CompileExpr::Compile (var.get_expr (), ctx, nullptr); std::string name = var.get_identifier (); // FIXME need name mangling @@ -79,7 +79,8 @@ class CompileItem : public HIRCompileBase rust_assert (ok); ::Btype *type = TyTyResolveCompile::compile (ctx, resolved_type); - Bexpression *value = CompileExpr::Compile (constant.get_expr (), ctx); + Bexpression *value + = CompileExpr::Compile (constant.get_expr (), ctx, nullptr); Bexpression *const_expr = ctx->get_backend ()->named_constant_expression ( type, constant.get_identifier (), value, constant.get_locus ()); diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust-compile-stmt.h index a777df658953..23b8fdc0e550 100644 --- a/gcc/rust/backend/rust-compile-stmt.h +++ b/gcc/rust/backend/rust-compile-stmt.h @@ -42,13 +42,13 @@ class CompileStmt : public HIRCompileBase void visit (HIR::ExprStmtWithBlock &stmt) override { ok = true; - translated = CompileExpr::Compile (stmt.get_expr (), ctx); + translated = CompileExpr::Compile (stmt.get_expr (), ctx, nullptr); } void visit (HIR::ExprStmtWithoutBlock &stmt) override { ok = true; - translated = CompileExpr::Compile (stmt.get_expr (), ctx); + translated = CompileExpr::Compile (stmt.get_expr (), ctx, nullptr); } void visit (HIR::LetStmt &stmt) override @@ -76,7 +76,8 @@ class CompileStmt : public HIRCompileBase return; } - Bexpression *init = CompileExpr::Compile (stmt.get_init_expr (), ctx); + Bexpression *init + = CompileExpr::Compile (stmt.get_init_expr (), ctx, nullptr); if (init == nullptr) return; diff --git a/gcc/rust/backend/rust-compile-struct-field-expr.h b/gcc/rust/backend/rust-compile-struct-field-expr.h index e3775247b964..393078764a20 100644 --- a/gcc/rust/backend/rust-compile-struct-field-expr.h +++ b/gcc/rust/backend/rust-compile-struct-field-expr.h @@ -30,11 +30,15 @@ class CompileStructExprField : public HIRCompileBase using Rust::Compile::HIRCompileBase::visit; public: - static Bexpression *Compile (HIR::StructExprField *field, Context *ctx) + static Bexpression *Compile (HIR::StructExprField *field, Context *ctx, + bool *terminated) { CompileStructExprField compiler (ctx); field->accept_vis (compiler); - rust_assert (compiler.translated != nullptr); + if (terminated && compiler.terminated) + *terminated = true; + else + rust_assert (compiler.translated != nullptr); return compiler.translated; } @@ -46,10 +50,11 @@ class CompileStructExprField : public HIRCompileBase private: CompileStructExprField (Context *ctx) - : HIRCompileBase (ctx), translated (nullptr) + : HIRCompileBase (ctx), translated (nullptr), terminated (false) {} Bexpression *translated; + bool terminated; }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-tyty.h b/gcc/rust/backend/rust-compile-tyty.h index 28db28971847..ba98ac014529 100644 --- a/gcc/rust/backend/rust-compile-tyty.h +++ b/gcc/rust/backend/rust-compile-tyty.h @@ -222,6 +222,11 @@ class TyTyCompile : public TyTy::TyVisitor = backend->named_type ("str", raw_str, Linemap::predeclared_location ()); } + void visit (TyTy::NeverType &) override + { + translated = backend->void_type (); + } + private: TyTyCompile (::Backend *backend) : backend (backend), translated (nullptr), diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index a2f524725a66..57f42482e38f 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -72,10 +72,14 @@ CompileExpr::visit (HIR::CallExpr &expr) // base struct was specified those fields are filed via accesors std::vector vals; expr.iterate_params ([&] (HIR::Expr *argument) mutable -> bool { - Bexpression *e = CompileExpr::Compile (argument, ctx); + Bexpression *e = CompileExpr::Compile (argument, ctx, &terminated); + if (terminated) + return false; vals.push_back (e); return true; }); + if (terminated) + return; translated = ctx->get_backend ()->constructor_expression (type, vals, @@ -84,15 +88,22 @@ CompileExpr::visit (HIR::CallExpr &expr) else { // must be a call to a function - Bexpression *fn = CompileExpr::Compile (expr.get_fnexpr (), ctx); + Bexpression *fn + = CompileExpr::Compile (expr.get_fnexpr (), ctx, &terminated); + if (terminated) + return; std::vector args; expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool { - Bexpression *compiled_expr = CompileExpr::Compile (p, ctx); + Bexpression *compiled_expr = CompileExpr::Compile (p, ctx, &terminated); + if (terminated) + return false; rust_assert (compiled_expr != nullptr); args.push_back (compiled_expr); return true; }); + if (terminated) + return; auto fncontext = ctx->peek_fn (); translated @@ -173,17 +184,24 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) std::vector args; // method receiver - Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx); + Bexpression *self + = CompileExpr::Compile (expr.get_receiver ().get (), ctx, &terminated); + if (terminated) + return; rust_assert (self != nullptr); args.push_back (self); // normal args expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool { - Bexpression *compiled_expr = CompileExpr::Compile (p, ctx); + Bexpression *compiled_expr = CompileExpr::Compile (p, ctx, &terminated); + if (terminated) + return false; rust_assert (compiled_expr != nullptr); args.push_back (compiled_expr); return true; }); + if (terminated) + return; auto fncontext = ctx->peek_fn (); translated @@ -234,34 +252,23 @@ CompileBlock::visit (HIR::BlockExpr &expr) for (auto &s : expr.get_statements ()) { auto compiled_expr = CompileStmt::Compile (s.get (), ctx); - if (compiled_expr == nullptr) - continue; - - if (result == nullptr) + if (compiled_expr != nullptr) { - Bstatement *final_stmt + Bstatement *compiled_stmt = ctx->get_backend ()->expression_statement (fnctx.fndecl, compiled_expr); - ctx->add_statement (final_stmt); - } - else - { - Bexpression *result_reference - = ctx->get_backend ()->var_expression (result, - s->get_locus_slow ()); - - Bstatement *assignment = ctx->get_backend ()->assignment_statement ( - fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); - ctx->add_statement (assignment); + ctx->add_statement (compiled_stmt); } } - if (expr.has_expr () && expr.tail_expr_reachable ()) + if (expr.has_expr ()) { // the previous passes will ensure this is a valid return // dead code elimination should remove any bad trailing expressions - Bexpression *compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx); - if (compiled_expr != nullptr) + bool terminated = false; + Bexpression *compiled_expr + = CompileExpr::Compile (expr.expr.get (), ctx, &terminated); + if (!terminated && compiled_expr != nullptr) { if (result == nullptr) { @@ -293,10 +300,13 @@ CompileBlock::visit (HIR::BlockExpr &expr) void CompileConditionalBlocks::visit (HIR::IfExpr &expr) { + Bexpression *condition_expr + = CompileExpr::Compile (expr.get_if_condition (), ctx, &terminated); + if (terminated) + return; + fncontext fnctx = ctx->peek_fn (); Bfunction *fndecl = fnctx.fndecl; - Bexpression *condition_expr - = CompileExpr::Compile (expr.get_if_condition (), ctx); Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); @@ -308,10 +318,13 @@ CompileConditionalBlocks::visit (HIR::IfExpr &expr) void CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) { + Bexpression *condition_expr + = CompileExpr::Compile (expr.get_if_condition (), ctx, &terminated); + if (terminated) + return; + fncontext fnctx = ctx->peek_fn (); Bfunction *fndecl = fnctx.fndecl; - Bexpression *condition_expr - = CompileExpr::Compile (expr.get_if_condition (), ctx); Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); Bblock *else_block @@ -325,10 +338,13 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) void CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) { + Bexpression *condition_expr + = CompileExpr::Compile (expr.get_if_condition (), ctx, &terminated); + if (terminated) + return; + fncontext fnctx = ctx->peek_fn (); Bfunction *fndecl = fnctx.fndecl; - Bexpression *condition_expr - = CompileExpr::Compile (expr.get_if_condition (), ctx); Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); @@ -342,10 +358,12 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) start_location, end_location); ctx->push_block (else_block); + bool else_terminated = false; Bstatement *else_stmt_decl = CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), ctx, - result); - ctx->add_statement (else_stmt_decl); + result, &else_terminated); + if (!else_terminated) + ctx->add_statement (else_stmt_decl); ctx->pop_block (); @@ -359,13 +377,13 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) void CompileStructExprField::visit (HIR::StructExprFieldIdentifierValue &field) { - translated = CompileExpr::Compile (field.get_value (), ctx); + translated = CompileExpr::Compile (field.get_value (), ctx, &terminated); } void CompileStructExprField::visit (HIR::StructExprFieldIndexValue &field) { - translated = CompileExpr::Compile (field.get_value (), ctx); + translated = CompileExpr::Compile (field.get_value (), ctx, &terminated); } void @@ -375,7 +393,7 @@ CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field) // existing code HIR::IdentifierExpr expr (field.get_mappings (), field.get_field_name (), field.get_locus ()); - translated = CompileExpr::Compile (&expr, ctx); + translated = CompileExpr::Compile (&expr, ctx, nullptr); } // Shared methods in compilation @@ -389,15 +407,31 @@ HIRCompileBase::compile_function_body ( { auto compiled_expr = CompileStmt::Compile (s.get (), ctx); if (compiled_expr != nullptr) + { + Bstatement *compiled_stmt + = ctx->get_backend ()->expression_statement (fndecl, compiled_expr); + ctx->add_statement (compiled_stmt); + } + } + + if (function_body->has_expr ()) + { + // the previous passes will ensure this is a valid return + // dead code elimination should remove any bad trailing expressions + bool terminated = false; + Bexpression *compiled_expr + = CompileExpr::Compile (function_body->expr.get (), ctx, &terminated); + + if (!terminated && compiled_expr != nullptr) { if (has_return_type) { std::vector retstmts; retstmts.push_back (compiled_expr); - auto ret - = ctx->get_backend ()->return_statement (fndecl, retstmts, - s->get_locus_slow ()); + auto ret = ctx->get_backend ()->return_statement ( + fndecl, retstmts, + function_body->get_final_expr ()->get_locus_slow ()); ctx->add_statement (ret); } else @@ -409,32 +443,6 @@ HIRCompileBase::compile_function_body ( } } } - - if (function_body->has_expr () && function_body->tail_expr_reachable ()) - { - // the previous passes will ensure this is a valid return - // dead code elimination should remove any bad trailing expressions - Bexpression *compiled_expr - = CompileExpr::Compile (function_body->expr.get (), ctx); - rust_assert (compiled_expr != nullptr); - - if (has_return_type) - { - std::vector retstmts; - retstmts.push_back (compiled_expr); - - auto ret = ctx->get_backend ()->return_statement ( - fndecl, retstmts, - function_body->get_final_expr ()->get_locus_slow ()); - ctx->add_statement (ret); - } - else - { - Bstatement *final_stmt - = ctx->get_backend ()->expression_statement (fndecl, compiled_expr); - ctx->add_statement (final_stmt); - } - } } } // namespace Compile diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index 25c35835ae09..2285abc5f1c8 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -42,7 +42,8 @@ class ASTLoweringBlock : public ASTLoweringBase resolver.translated); } - *terminated = resolver.terminated; + if (terminated != nullptr) + *terminated |= resolver.terminated; return resolver.translated; } @@ -75,7 +76,7 @@ class ASTLoweringIfBlock : public ASTLoweringBase resolver.translated->get_mappings ().get_hirid (), resolver.translated); } - *terminated = resolver.terminated; + *terminated |= resolver.terminated; return resolver.translated; } @@ -114,7 +115,7 @@ class ASTLoweringExprWithBlock : public ASTLoweringBase resolver.translated); } - *terminated = resolver.terminated; + *terminated |= resolver.terminated; return resolver.translated; } @@ -144,8 +145,8 @@ class ASTLoweringExprWithBlock : public ASTLoweringBase { std::vector outer_attribs; HIR::BlockExpr *loop_block - = ASTLoweringBlock::translate (expr.get_loop_block ().get (), - &terminated); + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), nullptr); + // TODO: Determine whether it is an infinite loop. HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index c59412f3cfc8..19d399806ab2 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -89,7 +89,7 @@ class ASTLoweringExpr : public ASTLoweringBase using Rust::HIR::ASTLoweringBase::visit; public: - static HIR::Expr *translate (AST::Expr *expr, bool *terminated = nullptr) + static HIR::Expr *translate (AST::Expr *expr, bool *terminated) { ASTLoweringExpr resolver; expr->accept_vis (resolver); @@ -109,7 +109,7 @@ class ASTLoweringExpr : public ASTLoweringBase expr->get_locus_slow ()); if (terminated != nullptr) - *terminated = resolver.terminated; + *terminated |= resolver.terminated; return resolver.translated; } @@ -140,7 +140,7 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector > tuple_elements; for (auto &e : expr.get_tuple_elems ()) { - HIR::Expr *t = ASTLoweringExpr::translate (e.get ()); + HIR::Expr *t = ASTLoweringExpr::translate (e.get (), &terminated); tuple_elements.push_back (std::unique_ptr (t)); } @@ -182,10 +182,10 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::ReturnExpr &expr) override { - terminated = true; HIR::Expr *return_expr = expr.has_returned_expr () - ? ASTLoweringExpr::translate (expr.get_returned_expr ().get ()) + ? ASTLoweringExpr::translate (expr.get_returned_expr ().get (), + &terminated) : nullptr; auto crate_num = mappings->get_current_crate (); @@ -195,16 +195,19 @@ class ASTLoweringExpr : public ASTLoweringBase translated = new HIR::ReturnExpr (mapping, expr.get_locus (), std::unique_ptr (return_expr)); + terminated = true; } void visit (AST::CallExpr &expr) override { std::vector outer_attribs; HIR::Expr *func - = ASTLoweringExpr::translate (expr.get_function_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_function_expr ().get (), + &terminated); + std::vector > params; expr.iterate_params ([&] (AST::Expr *p) mutable -> bool { - auto trans = ASTLoweringExpr::translate (p); + auto trans = ASTLoweringExpr::translate (p, &terminated); params.push_back (std::unique_ptr (trans)); return true; }); @@ -228,11 +231,12 @@ class ASTLoweringExpr : public ASTLoweringBase = lower_path_expr_seg (expr.get_method_name ()); HIR::Expr *receiver - = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_receiver_expr ().get (), + &terminated); std::vector > params; expr.iterate_params ([&] (AST::Expr *p) mutable -> bool { - auto trans = ASTLoweringExpr::translate (p); + auto trans = ASTLoweringExpr::translate (p, &terminated); params.push_back (std::unique_ptr (trans)); return true; }); @@ -250,8 +254,10 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::AssignmentExpr &expr) override { - HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); - HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + HIR::Expr *lhs + = ASTLoweringExpr::translate (expr.get_left_expr ().get (), &terminated); + HIR::Expr *rhs + = ASTLoweringExpr::translate (expr.get_right_expr ().get (), &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -280,6 +286,7 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector inner_attribs; expr.get_array_elems ()->accept_vis (*this); + rust_assert (translated_array_elems != nullptr); HIR::ArrayElems *elems = translated_array_elems; @@ -296,10 +303,11 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::ArrayIndexExpr &expr) override { std::vector outer_attribs; + HIR::Expr *array_expr - = ASTLoweringExpr::translate (expr.get_array_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_array_expr ().get (), &terminated); HIR::Expr *array_index_expr - = ASTLoweringExpr::translate (expr.get_index_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_index_expr ().get (), &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -317,7 +325,8 @@ class ASTLoweringExpr : public ASTLoweringBase { std::vector > elements; elems.iterate ([&] (AST::Expr *elem) mutable -> bool { - HIR::Expr *translated_elem = ASTLoweringExpr::translate (elem); + HIR::Expr *translated_elem + = ASTLoweringExpr::translate (elem, &terminated); elements.push_back (std::unique_ptr (translated_elem)); return true; }); @@ -328,9 +337,12 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::ArrayElemsCopied &elems) override { HIR::Expr *element - = ASTLoweringExpr::translate (elems.get_elem_to_copy ().get ()); + = ASTLoweringExpr::translate (elems.get_elem_to_copy ().get (), + &terminated); + HIR::Expr *num_copies - = ASTLoweringExpr::translate (elems.get_num_copies ().get ()); + = ASTLoweringExpr::translate (elems.get_num_copies ().get (), + &terminated); size_t folded; if (!ArrayCapacityConstant::fold (elems.get_num_copies ().get (), &folded)) @@ -391,9 +403,11 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::ArithmeticOrLogicalExpr &expr) override { - HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + HIR::Expr *lhs + = ASTLoweringExpr::translate (expr.get_left_expr ().get (), &terminated); rust_assert (lhs != nullptr); - HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + HIR::Expr *rhs + = ASTLoweringExpr::translate (expr.get_right_expr ().get (), &terminated); rust_assert (rhs != nullptr); auto crate_num = mappings->get_current_crate (); @@ -411,9 +425,11 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::ComparisonExpr &expr) override { - HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + HIR::Expr *lhs + = ASTLoweringExpr::translate (expr.get_left_expr ().get (), &terminated); rust_assert (lhs != nullptr); - HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + HIR::Expr *rhs + = ASTLoweringExpr::translate (expr.get_right_expr ().get (), &terminated); rust_assert (rhs != nullptr); auto crate_num = mappings->get_current_crate (); @@ -429,9 +445,13 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::LazyBooleanExpr &expr) override { - HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + // FIXME: The termination check is not correct and neither the codegen. + // See also Rust::Compile::CompileExpr::visit (Rust::HIR::LazyBooleanExpr&). + HIR::Expr *lhs + = ASTLoweringExpr::translate (expr.get_left_expr ().get (), &terminated); rust_assert (lhs != nullptr); - HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + HIR::Expr *rhs + = ASTLoweringExpr::translate (expr.get_right_expr ().get (), &terminated); rust_assert (rhs != nullptr); auto crate_num = mappings->get_current_crate (); @@ -450,7 +470,8 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector outer_attribs; HIR::Expr *negated_value - = ASTLoweringExpr::translate (expr.get_negated_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_negated_expr ().get (), + &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -505,22 +526,25 @@ class ASTLoweringExpr : public ASTLoweringBase gcc_unreachable (); } - HIR::Expr *asignee_expr - = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + HIR::Expr *assignee_expr + = ASTLoweringExpr::translate (expr.get_left_expr ().get (), &terminated); + rust_assert (!terminated); + HIR::Expr *value - = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_right_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); + HIR::Expr *operator_expr - = new HIR::ArithmeticOrLogicalExpr (mapping, asignee_expr->clone_expr (), + = new HIR::ArithmeticOrLogicalExpr (mapping, assignee_expr->clone_expr (), std::unique_ptr (value), op, expr.get_locus ()); translated = new HIR::AssignmentExpr (mapping, - std::unique_ptr (asignee_expr), + std::unique_ptr (assignee_expr), std::unique_ptr (operator_expr), expr.get_locus ()); } @@ -540,7 +564,10 @@ class ASTLoweringExpr : public ASTLoweringBase if (struct_expr.has_struct_base ()) { HIR::Expr *translated_base = ASTLoweringExpr::translate ( - struct_expr.get_struct_base ().get_base_struct ().get ()); + struct_expr.get_struct_base ().get_base_struct ().get (), + &terminated); + rust_assert (!terminated); + base = new HIR::StructBase (std::unique_ptr (translated_base)); } @@ -548,7 +575,7 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector > fields; struct_expr.iterate ([&] (AST::StructExprField *field) mutable -> bool { HIR::StructExprField *translated - = ASTLowerStructExprField::translate (field); + = ASTLowerStructExprField::translate (field, &terminated); fields.push_back (std::unique_ptr (translated)); return true; }); @@ -571,7 +598,8 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector outer_attribs; HIR::Expr *paren_expr - = ASTLoweringExpr::translate (expr.get_expr_in_parens ().get ()); + = ASTLoweringExpr::translate (expr.get_expr_in_parens ().get (), + &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -590,7 +618,8 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector outer_attribs; HIR::Expr *receiver - = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_receiver_expr ().get (), + &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -619,7 +648,8 @@ class ASTLoweringExpr : public ASTLoweringBase HIR::Lifetime break_label = lower_lifetime (expr.get_label ()); HIR::Expr *break_expr = expr.has_break_expr () - ? ASTLoweringExpr::translate (expr.get_break_expr ().get ()) + ? ASTLoweringExpr::translate (expr.get_break_expr ().get (), + &terminated) : nullptr; auto crate_num = mappings->get_current_crate (); @@ -631,6 +661,7 @@ class ASTLoweringExpr : public ASTLoweringBase std ::move (break_label), std::unique_ptr (break_expr), std::move (outer_attribs)); + terminated = true; } void visit (AST::ContinueExpr &expr) override @@ -646,6 +677,7 @@ class ASTLoweringExpr : public ASTLoweringBase translated = new HIR::ContinueExpr (mapping, expr.get_locus (), std ::move (break_label), std::move (outer_attribs)); + terminated = true; } void visit (AST::BorrowExpr &expr) override @@ -653,7 +685,8 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector outer_attribs; HIR::Expr *borrow_lvalue - = ASTLoweringExpr::translate (expr.get_borrowed_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_borrowed_expr ().get (), + &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -672,7 +705,8 @@ class ASTLoweringExpr : public ASTLoweringBase std::vector outer_attribs; HIR::Expr *dref_lvalue - = ASTLoweringExpr::translate (expr.get_dereferenced_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_dereferenced_expr ().get (), + &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h index 3ddc62cad2f0..aa5abfe9ccdd 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.h +++ b/gcc/rust/hir/rust-ast-lower-implitem.h @@ -64,7 +64,8 @@ class ASTLowerImplItem : public ASTLoweringBase HIR::Visibility vis = HIR::Visibility::create_public (); HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); - HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ()); + HIR::Expr *expr + = ASTLoweringExpr::translate (constant.get_expr ().get (), nullptr); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index 18ead3c788b5..c234e3e6aa12 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -205,7 +205,8 @@ class ASTLoweringItem : public ASTLoweringBase HIR::Visibility vis = HIR::Visibility::create_public (); HIR::Type *type = ASTLoweringType::translate (var.get_type ().get ()); - HIR::Expr *expr = ASTLoweringExpr::translate (var.get_expr ().get ()); + HIR::Expr *expr + = ASTLoweringExpr::translate (var.get_expr ().get (), nullptr); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, var.get_node_id (), @@ -231,7 +232,8 @@ class ASTLoweringItem : public ASTLoweringBase HIR::Visibility vis = HIR::Visibility::create_public (); HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); - HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ()); + HIR::Expr *expr + = ASTLoweringExpr::translate (constant.get_expr ().get (), nullptr); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h index e15714c7218d..ba44bc3e19f5 100644 --- a/gcc/rust/hir/rust-ast-lower-stmt.h +++ b/gcc/rust/hir/rust-ast-lower-stmt.h @@ -40,7 +40,7 @@ class ASTLoweringStmt : public ASTLoweringBase ASTLoweringStmt resolver; stmt->accept_vis (resolver); rust_assert (resolver.translated != nullptr); - *terminated = resolver.terminated; + *terminated |= resolver.terminated; return resolver.translated; } @@ -59,7 +59,8 @@ class ASTLoweringStmt : public ASTLoweringBase translated = new HIR::ExprStmtWithBlock (mapping, std::unique_ptr (expr), - stmt.get_locus ()); + stmt.get_locus (), + !stmt.is_semicolon_followed ()); mappings->insert_location (crate_num, mapping.get_hirid (), stmt.get_locus ()); mappings->insert_hir_stmt (crate_num, mapping.get_hirid (), translated); @@ -93,7 +94,8 @@ class ASTLoweringStmt : public ASTLoweringBase : nullptr; HIR::Expr *init_expression = stmt.has_init_expr () - ? ASTLoweringExpr::translate (stmt.get_init_expr ().get ()) + ? ASTLoweringExpr::translate (stmt.get_init_expr ().get (), + &terminated) : nullptr; auto crate_num = mappings->get_current_crate (); diff --git a/gcc/rust/hir/rust-ast-lower-struct-field-expr.h b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h index 3b313a784765..660fcbd089bd 100644 --- a/gcc/rust/hir/rust-ast-lower-struct-field-expr.h +++ b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h @@ -30,7 +30,8 @@ class ASTLowerStructExprField : public ASTLoweringBase using Rust::HIR::ASTLoweringBase::visit; public: - static HIR::StructExprField *translate (AST::StructExprField *field) + static HIR::StructExprField *translate (AST::StructExprField *field, + bool *terminated) { ASTLowerStructExprField compiler; field->accept_vis (compiler); @@ -44,6 +45,9 @@ class ASTLowerStructExprField : public ASTLoweringBase compiler.translated->get_mappings ().get_hirid (), field->get_locus_slow ()); + if (terminated) + *terminated |= compiler.terminated; + return compiler.translated; } @@ -56,9 +60,10 @@ class ASTLowerStructExprField : public ASTLoweringBase void visit (AST::StructExprFieldIdentifier &field) override; private: - ASTLowerStructExprField () : translated (nullptr) {} + ASTLowerStructExprField () : translated (nullptr), terminated (false) {} HIR::StructExprField *translated; + bool terminated; }; } // namespace HIR diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 318d1261524c..043159d93e8e 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -188,7 +188,7 @@ class ASTLoweringType : public ASTLoweringBase HIR::Type *translated_type = ASTLoweringType::translate (type.get_elem_type ().get ()); HIR::Expr *array_size - = ASTLoweringExpr::translate (type.get_size_expr ().get ()); + = ASTLoweringExpr::translate (type.get_size_expr ().get (), nullptr); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index 0bacdd216d7b..7383f8aa0b55 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -71,26 +71,14 @@ ASTLoweringBlock::visit (AST::BlockExpr &expr) std::vector > block_stmts; bool block_did_terminate = false; expr.iterate_stmts ([&] (AST::Stmt *s) mutable -> bool { - bool terminated = false; - auto translated_stmt = ASTLoweringStmt::translate (s, &terminated); - block_stmts.push_back (std::unique_ptr (translated_stmt)); - block_did_terminate = terminated; - return !block_did_terminate; - }); - - // if there was a return expression everything after that becomes - // unreachable code. This can be detected for any AST NodeIDs that have no - // associated HIR Mappings - expr.iterate_stmts ([&] (AST::Stmt *s) -> bool { - HirId ref; - if (!mappings->lookup_node_to_hir (mappings->get_current_crate (), - s->get_node_id (), &ref)) + if (block_did_terminate) rust_warning_at (s->get_locus_slow (), 0, "unreachable statement"); + auto translated_stmt = ASTLoweringStmt::translate (s, &block_did_terminate); + block_stmts.push_back (std::unique_ptr (translated_stmt)); return true; }); - bool tail_reachable = expr.has_tail_expr () && !block_did_terminate; if (expr.has_tail_expr () && block_did_terminate) { // warning unreachable tail expressions @@ -102,7 +90,7 @@ ASTLoweringBlock::visit (AST::BlockExpr &expr) if (expr.has_tail_expr ()) { tail_expr = (HIR::ExprWithoutBlock *) ASTLoweringExpr::translate ( - expr.get_tail_expr ().get ()); + expr.get_tail_expr ().get (), &block_did_terminate); } auto crate_num = mappings->get_current_crate (); @@ -112,22 +100,19 @@ ASTLoweringBlock::visit (AST::BlockExpr &expr) translated = new HIR::BlockExpr (mapping, std::move (block_stmts), std::unique_ptr (tail_expr), - tail_reachable, std::move (inner_attribs), + !block_did_terminate, std::move (inner_attribs), std::move (outer_attribs), expr.get_locus ()); - terminated = block_did_terminate; } void ASTLoweringIfBlock::visit (AST::IfExpr &expr) { - bool ignored_terminated = false; HIR::Expr *condition = ASTLoweringExpr::translate (expr.get_condition_expr ().get (), - &ignored_terminated); + &terminated); HIR::BlockExpr *block - = ASTLoweringBlock::translate (expr.get_if_block ().get (), - &ignored_terminated); + = ASTLoweringBlock::translate (expr.get_if_block ().get (), nullptr); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -143,7 +128,8 @@ void ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) { HIR::Expr *condition - = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_condition_expr ().get (), + &terminated); bool if_block_terminated = false; bool else_block_termianted = false; @@ -155,7 +141,7 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) = ASTLoweringBlock::translate (expr.get_else_block ().get (), &else_block_termianted); - terminated = if_block_terminated && else_block_termianted; + terminated |= if_block_terminated && else_block_termianted; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -174,15 +160,18 @@ void ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr) { HIR::Expr *condition - = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); + = ASTLoweringExpr::translate (expr.get_condition_expr ().get (), + &terminated); - bool ignored_terminated = false; + bool if_block_terminated = false; + bool conseq_if_terminated = false; HIR::BlockExpr *block = ASTLoweringBlock::translate (expr.get_if_block ().get (), - &ignored_terminated); + &if_block_terminated); HIR::IfExpr *conseq_if_expr = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get (), - &ignored_terminated); + &conseq_if_terminated); + terminated |= if_block_terminated && conseq_if_terminated; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -201,7 +190,8 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr) void ASTLowerStructExprField::visit (AST::StructExprFieldIdentifierValue &field) { - HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); + HIR::Expr *value + = ASTLoweringExpr::translate (field.get_value ().get (), &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, field.get_node_id (), @@ -216,7 +206,8 @@ ASTLowerStructExprField::visit (AST::StructExprFieldIdentifierValue &field) void ASTLowerStructExprField::visit (AST::StructExprFieldIndexValue &field) { - HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); + HIR::Expr *value + = ASTLoweringExpr::translate (field.get_value ().get (), &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, field.get_node_id (), @@ -249,7 +240,7 @@ ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) { std::vector outer_attribs; HIR::BlockExpr *loop_block - = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated); + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), nullptr); HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); HIR::Expr *loop_condition diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 1748c6ae7c8c..92b782658ee6 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -1368,6 +1368,8 @@ class StructExprField virtual void accept_vis (HIRVisitor &vis) = 0; + virtual Expr *get_value () = 0; + Analysis::NodeMapping &get_mappings () { return mappings; } Location get_locus () { return locus; } @@ -1402,6 +1404,8 @@ class StructExprFieldIdentifier : public StructExprField void accept_vis (HIRVisitor &vis) override; + Expr *get_value () override final { return nullptr; } + Identifier get_field_name () const { return field_name; } protected: @@ -1448,7 +1452,7 @@ class StructExprFieldWithVal : public StructExprField public: std::string as_string () const override; - Expr *get_value () { return value.get (); } + Expr *get_value () override final { return value.get (); } }; // Identifier and value variant of StructExprField HIR node @@ -2498,7 +2502,7 @@ class BlockExpr : public ExprWithBlock std::vector inner_attrs; std::vector > statements; - std::unique_ptr expr; // inlined from Statements + std::unique_ptr expr; // inlined from Statements bool tail_reachable; Location locus; @@ -2511,11 +2515,11 @@ class BlockExpr : public ExprWithBlock // Returns whether the block contains an expression bool has_expr () const { return expr != nullptr; } - bool tail_expr_reachable () const { return tail_reachable; } + bool is_tail_reachable () const { return tail_reachable; } BlockExpr (Analysis::NodeMapping mappings, std::vector > block_statements, - std::unique_ptr block_expr, bool tail_reachable, + std::unique_ptr block_expr, bool tail_reachable, std::vector inner_attribs, std::vector outer_attribs, Location locus) : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), @@ -2531,7 +2535,7 @@ class BlockExpr : public ExprWithBlock { // guard to protect from null pointer dereference if (other.expr != nullptr) - expr = other.expr->clone_expr_without_block (); + expr = other.expr->clone_expr (); statements.reserve (other.statements.size ()); for (const auto &e : other.statements) @@ -2543,7 +2547,7 @@ class BlockExpr : public ExprWithBlock { ExprWithBlock::operator= (other); // statements = other.statements; - expr = other.expr->clone_expr_without_block (); + expr = other.expr->clone_expr (); inner_attrs = other.inner_attrs; locus = other.locus; // outer_attrs = other.outer_attrs; @@ -2589,7 +2593,7 @@ class BlockExpr : public ExprWithBlock return statements[statements.size () - 1]->get_locus_slow (); } - std::unique_ptr &get_final_expr () { return expr; } + std::unique_ptr &get_final_expr () { return expr; } std::vector > &get_statements () { return statements; } diff --git a/gcc/rust/hir/tree/rust-hir-stmt.h b/gcc/rust/hir/tree/rust-hir-stmt.h index 3384aaac9ac0..baff6fd68685 100644 --- a/gcc/rust/hir/tree/rust-hir-stmt.h +++ b/gcc/rust/hir/tree/rust-hir-stmt.h @@ -193,13 +193,16 @@ class ExprStmtWithoutBlock : public ExprStmt class ExprStmtWithBlock : public ExprStmt { std::unique_ptr expr; + bool must_be_unit; public: std::string as_string () const override; ExprStmtWithBlock (Analysis::NodeMapping mappings, - std::unique_ptr expr, Location locus) - : ExprStmt (std::move (mappings), locus), expr (std::move (expr)) + std::unique_ptr expr, Location locus, + bool must_be_unit) + : ExprStmt (std::move (mappings), locus), expr (std::move (expr)), + must_be_unit (must_be_unit) {} // Copy constructor with clone @@ -224,6 +227,8 @@ class ExprStmtWithBlock : public ExprStmt ExprWithBlock *get_expr () { return expr.get (); } + bool is_unit_check_needed () { return must_be_unit; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 96971697896e..2d685799eeda 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -7022,11 +7022,9 @@ Parser::parse_expr_stmt ( } } -/* Parses a expression statement containing an expression with block. - * Disambiguates internally. */ template -std::unique_ptr -Parser::parse_expr_stmt_with_block ( +std::unique_ptr +Parser::parse_expr_with_block ( std::vector outer_attrs) { std::unique_ptr expr_parsed = nullptr; @@ -7113,9 +7111,23 @@ Parser::parse_expr_stmt_with_block ( return nullptr; } + return expr_parsed; +} + +/* Parses a expression statement containing an expression with block. + * Disambiguates internally. */ +template +std::unique_ptr +Parser::parse_expr_stmt_with_block ( + std::vector outer_attrs) +{ + auto expr_parsed = parse_expr_with_block (std::move (outer_attrs)); + auto locus = expr_parsed->get_locus (); + // return expr stmt created from expr return std::unique_ptr ( - new AST::ExprStmtWithBlock (std::move (expr_parsed), t->get_locus ())); + new AST::ExprStmtWithBlock (std::move (expr_parsed), locus, + lexer.peek_token ()->get_id () == SEMICOLON)); } /* Parses an expression statement containing an expression without block. @@ -7286,7 +7298,7 @@ Parser::parse_block_expr ( // parse statements and expression std::vector> stmts; - std::unique_ptr expr = nullptr; + std::unique_ptr expr = nullptr; const_TokenPtr t = lexer.peek_token (); while (t->get_id () != RIGHT_CURLY) @@ -7591,11 +7603,23 @@ Parser::parse_return_expr ( locus = lexer.peek_token ()->get_locus () - 7; } + std::unique_ptr returned_expr = nullptr; + // parse expression to return, if it exists - ParseRestrictions restrictions; - restrictions.expr_can_be_null = true; - std::unique_ptr returned_expr - = parse_expr (std::vector (), restrictions); + // FIXME: parse_expr always skips at least one token + switch (lexer.peek_token ()->get_id ()) + { + case SEMICOLON: + case RIGHT_CURLY: + case RIGHT_PAREN: + case RIGHT_SQUARE: + case COMMA: + break; + default: + returned_expr + = parse_expr (std::vector (), ParseRestrictions ()); + break; + } return std::unique_ptr ( new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs), @@ -11438,6 +11462,29 @@ Parser::parse_struct_pattern_field_partial ( } } +template +ExprOrStmt +Parser::parse_stmt_or_expr_with_block ( + std::vector outer_attrs) +{ + auto expr = parse_expr_with_block (std::move (outer_attrs)); + auto tok = lexer.peek_token (); + + // tail expr in a block expr + if (tok->get_id () == RIGHT_CURLY) + return ExprOrStmt (std::move (expr)); + + // internal block expr must either have semicolons followed, or evaluate to () + auto locus = expr->get_locus_slow (); + std::unique_ptr stmt ( + new AST::ExprStmtWithBlock (std::move (expr), locus, + tok->get_id () == SEMICOLON)); + if (tok->get_id () == SEMICOLON) + lexer.skip_token (); + + return ExprOrStmt (std::move (stmt)); +} + /* Parses a statement or expression (depending on whether a trailing semicolon * exists). Useful for block expressions where it cannot be determined through * lookahead whether it is a statement or expression to be parsed. */ @@ -11508,9 +11555,7 @@ Parser::parse_stmt_or_expr_without_block () { case LEFT_CURLY: { // unsafe block - std::unique_ptr stmt ( - parse_expr_stmt_with_block (std::move (outer_attrs))); - return ExprOrStmt (std::move (stmt)); + return parse_stmt_or_expr_with_block (std::move (outer_attrs)); } case TRAIT: { // unsafe trait @@ -11577,11 +11622,7 @@ Parser::parse_stmt_or_expr_without_block () case MATCH_TOK: case LEFT_CURLY: case ASYNC: { - // all expressions with block, so cannot be final expr without block in - // function - std::unique_ptr stmt ( - parse_expr_stmt_with_block (std::move (outer_attrs))); - return ExprOrStmt (std::move (stmt)); + return parse_stmt_or_expr_with_block (std::move (outer_attrs)); } case LIFETIME: { /* FIXME: are there any expressions without blocks that can have @@ -11592,9 +11633,7 @@ Parser::parse_stmt_or_expr_without_block () && (t2->get_id () == LOOP || t2->get_id () == WHILE || t2->get_id () == FOR)) { - std::unique_ptr stmt ( - parse_expr_stmt_with_block (std::move (outer_attrs))); - return ExprOrStmt (std::move (stmt)); + return parse_stmt_or_expr_with_block (std::move (outer_attrs)); } else { diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index f6faa962fce4..47f55ea65cb8 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -27,7 +27,7 @@ namespace Rust { * probably take up the same amount of space. */ struct ExprOrStmt { - std::unique_ptr expr; + std::unique_ptr expr; std::unique_ptr stmt; /* I was going to resist the urge to make this a real class and make it POD, @@ -35,9 +35,7 @@ struct ExprOrStmt * constructor. */ // expression constructor - ExprOrStmt (std::unique_ptr expr) - : expr (std::move (expr)) - {} + ExprOrStmt (std::unique_ptr expr) : expr (std::move (expr)) {} // statement constructor ExprOrStmt (std::unique_ptr stmt) : stmt (std::move (stmt)) {} @@ -63,9 +61,7 @@ struct ExprOrStmt private: // private constructor only used for creating error state expr or stmt objects - ExprOrStmt (AST::ExprWithoutBlock *expr, AST::Stmt *stmt) - : expr (expr), stmt (stmt) - {} + ExprOrStmt (AST::Expr *expr, AST::Stmt *stmt) : expr (expr), stmt (stmt) {} // make this work: have a disambiguation specifically for known statements // (i.e. ';' and 'let'). then, have a special "parse expr or stmt" function @@ -487,6 +483,8 @@ template class Parser ParseRestrictions restrictions = ParseRestrictions ()); // Expression-related (non-Pratt parsed) + std::unique_ptr + parse_expr_with_block (std::vector outer_attrs); std::unique_ptr parse_expr_without_block (std::vector outer_attrs = std::vector ()); @@ -592,6 +590,8 @@ template class Parser parse_expr_stmt_without_block (std::vector outer_attrs); ExprOrStmt parse_stmt_or_expr_without_block (); ExprOrStmt + parse_stmt_or_expr_with_block (std::vector outer_attrs); + ExprOrStmt parse_macro_invocation_maybe_semi (std::vector outer_attrs); ExprOrStmt parse_path_based_stmt_or_expr (std::vector outer_attrs); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index cb2f2502f03c..08f1cc4cf6ba 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -147,7 +147,7 @@ class TypeCheckExpr : public TypeCheckBase { if (!expr.has_return_expr ()) { - infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); return; } @@ -166,6 +166,8 @@ class TypeCheckExpr : public TypeCheckBase fn_return_tyty->append_reference (expr_ty->get_ref ()); for (auto &ref : infered->get_combined_refs ()) fn_return_tyty->append_reference (ref); + + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); } void visit (HIR::CallExpr &expr) override @@ -624,17 +626,28 @@ class TypeCheckExpr : public TypeCheckBase auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block (), inside_loop); - infered = if_blk_resolved->unify (else_blk_resolved); + if (if_blk_resolved->get_kind () == TyTy::NEVER) + infered = else_blk_resolved; + else if (else_blk_resolved->get_kind () == TyTy::NEVER) + infered = if_blk_resolved; + else + infered = if_blk_resolved->unify (else_blk_resolved); } void visit (HIR::IfExprConseqIf &expr) override { TypeCheckExpr::Resolve (expr.get_if_condition (), false); - auto if_blk = TypeCheckExpr::Resolve (expr.get_if_block (), inside_loop); - auto else_blk + auto if_blk_resolved + = TypeCheckExpr::Resolve (expr.get_if_block (), inside_loop); + auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_conseq_if_expr (), inside_loop); - infered = if_blk->unify (else_blk); + if (if_blk_resolved->get_kind () == TyTy::NEVER) + infered = else_blk_resolved; + else if (else_blk_resolved->get_kind () == TyTy::NEVER) + infered = if_blk_resolved; + else + infered = if_blk_resolved->unify (else_blk_resolved); } void visit (HIR::BlockExpr &expr) override; @@ -919,7 +932,7 @@ class TypeCheckExpr : public TypeCheckBase context->swap_head_loop_context (unified_ty); } - infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); } void visit (HIR::ContinueExpr &expr) override @@ -931,7 +944,7 @@ class TypeCheckExpr : public TypeCheckBase return; } - infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); } void visit (HIR::BorrowExpr &expr) override diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 44fe94346a9c..1205dceceee4 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -82,7 +82,8 @@ class TypeCheckItem : public TypeCheckBase context->pop_return_type (); - expected_ret_tyty->unify (block_expr_ty); + if (block_expr_ty->get_kind () != TyTy::NEVER) + expected_ret_tyty->unify (block_expr_ty); } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index e52368a67657..f6b5a1462469 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -42,6 +42,12 @@ class TypeCheckStmt : public TypeCheckBase void visit (HIR::ExprStmtWithBlock &stmt) override { infered = TypeCheckExpr::Resolve (stmt.get_expr (), inside_loop); + + if (stmt.is_unit_check_needed () && infered->get_kind () != TyTy::NEVER) + { + auto unit = new TyTy::TupleType (stmt.get_mappings ().get_hirid ()); + infered = unit->unify (infered); + } } void visit (HIR::ExprStmtWithoutBlock &stmt) override diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index c8394c8dcbe5..dcfa5b5eb7f6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -123,14 +123,7 @@ TypeResolution::Resolve (HIR::Crate &crate) void TypeCheckExpr::visit (HIR::BlockExpr &expr) { - TyTy::BaseType *block_tyty - = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); - expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool { - bool is_final_stmt = expr.is_final_stmt (s); - bool has_final_expr = expr.has_expr () && expr.tail_expr_reachable (); - bool stmt_is_final_expr = is_final_stmt && !has_final_expr; - auto resolved = TypeCheckStmt::Resolve (s, inside_loop); if (resolved == nullptr) { @@ -138,29 +131,17 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) return false; } - if (stmt_is_final_expr) - { - delete block_tyty; - block_tyty = resolved; - } - else if (!resolved->is_unit ()) - { - rust_error_at (s->get_locus_slow (), "expected () got %s", - resolved->as_string ().c_str ()); - } - return true; }); if (expr.has_expr ()) - { - delete block_tyty; - - block_tyty - = TypeCheckExpr::Resolve (expr.get_final_expr ().get (), inside_loop); - } - - infered = block_tyty->clone (); + infered + = TypeCheckExpr::Resolve (expr.get_final_expr ().get (), inside_loop) + ->clone (); + else if (expr.is_tail_reachable ()) + infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); + else + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); } // RUST_HIR_TYPE_CHECK_STRUCT_FIELD diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index db43cbd3f351..4f2ab9eca87b 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -99,6 +99,7 @@ class SubstMapper : public TyTy::TyVisitor void visit (TyTy::ReferenceType &) override { gcc_unreachable (); } void visit (TyTy::ParamType &) override { gcc_unreachable (); } void visit (TyTy::StrType &) override { gcc_unreachable (); } + void visit (TyTy::NeverType &) override { gcc_unreachable (); } private: SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus) @@ -157,6 +158,7 @@ class SubstMapperInternal : public TyTy::TyVisitor void visit (TyTy::ReferenceType &) override { gcc_unreachable (); } void visit (TyTy::ParamType &) override { gcc_unreachable (); } void visit (TyTy::StrType &) override { gcc_unreachable (); } + void visit (TyTy::NeverType &) override { gcc_unreachable (); } private: SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings) @@ -211,6 +213,7 @@ class SubstMapperFromExisting : public TyTy::TyVisitor void visit (TyTy::ReferenceType &) override { gcc_unreachable (); } void visit (TyTy::ParamType &) override { gcc_unreachable (); } void visit (TyTy::StrType &) override { gcc_unreachable (); } + void visit (TyTy::NeverType &) override { gcc_unreachable (); } private: SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver) diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h index 953770e3621a..2ab8abbdfcb1 100644 --- a/gcc/rust/typecheck/rust-tycheck-dump.h +++ b/gcc/rust/typecheck/rust-tycheck-dump.h @@ -107,7 +107,7 @@ class TypeResolverDump : public TypeCheckBase return true; }); - if (expr.has_expr () && expr.tail_expr_reachable ()) + if (expr.has_expr ()) { dump += indent (); expr.expr->accept_vis (*this); diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h index 4171da5e94e0..2aba29803d94 100644 --- a/gcc/rust/typecheck/rust-tyty-call.h +++ b/gcc/rust/typecheck/rust-tyty-call.h @@ -53,6 +53,7 @@ class TypeCheckCallExpr : private TyVisitor void visit (ReferenceType &type) override { gcc_unreachable (); } void visit (ParamType &) override { gcc_unreachable (); } void visit (StrType &) override { gcc_unreachable (); } + void visit (NeverType &) override { gcc_unreachable (); } // tuple-structs void visit (ADTType &type) override; @@ -100,6 +101,7 @@ class TypeCheckMethodCallExpr : private TyVisitor void visit (ReferenceType &type) override { gcc_unreachable (); } void visit (ParamType &) override { gcc_unreachable (); } void visit (StrType &) override { gcc_unreachable (); } + void visit (NeverType &) override { gcc_unreachable (); } // FIXME void visit (FnPtr &type) override { gcc_unreachable (); } diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index e2e0d08e9bc9..7b08f5ae9e5c 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -84,6 +84,8 @@ class BaseCmp : public TyVisitor virtual void visit (StrType &) override { ok = false; } + virtual void visit (NeverType &) override { ok = false; } + protected: BaseCmp (BaseType *base) : mappings (Analysis::Mappings::get ()), @@ -806,6 +808,21 @@ class StrCmp : public BaseCmp StrType *base; }; +class NeverCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + NeverCmp (NeverType *base) : BaseCmp (base), base (base) {} + + void visit (NeverType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + NeverType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index c23cbc1a749d..fe88b03af0d2 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -242,6 +242,14 @@ class BaseRules : public TyVisitor type.as_string ().c_str ()); } + virtual void visit (NeverType &type) override + { + Location ref_locus = mappings->lookup_location (type.get_ref ()); + rust_error_at (ref_locus, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + protected: BaseRules (BaseType *base) : mappings (Analysis::Mappings::get ()), @@ -1087,6 +1095,21 @@ class StrRules : public BaseRules StrType *base; }; +class NeverRules : public BaseRules +{ + using Rust::TyTy::BaseRules::visit; + +public: + NeverRules (NeverType *base) : BaseRules (base), base (base) {} + + virtual void visit (NeverType &type) override { resolved = type.clone (); } + +private: + BaseType *get_base () override { return base; } + + NeverType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h index 453a3b6bc864..0ed7eef35a65 100644 --- a/gcc/rust/typecheck/rust-tyty-visitor.h +++ b/gcc/rust/typecheck/rust-tyty-visitor.h @@ -44,6 +44,7 @@ class TyVisitor virtual void visit (ReferenceType &type) = 0; virtual void visit (ParamType &type) = 0; virtual void visit (StrType &type) = 0; + virtual void visit (NeverType &type) = 0; }; } // namespace TyTy diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 8f2faeccff67..c77d72212e9b 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -1304,6 +1304,38 @@ StrType::is_equal (const BaseType &other) const return get_kind () == other.get_kind (); } +void +NeverType::accept_vis (TyVisitor &vis) +{ + vis.visit (*this); +} + +std::string +NeverType::as_string () const +{ + return "!"; +} + +BaseType * +NeverType::unify (BaseType *other) +{ + NeverRules r (this); + return r.unify (other); +} + +bool +NeverType::can_eq (BaseType *other) +{ + NeverCmp r (this); + return r.can_eq (other); +} + +BaseType * +NeverType::clone () +{ + return new NeverType (get_ref (), get_ty_ref (), get_combined_refs ()); +} + // rust-tyty-call.h void diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index c428c4c6c6cd..1ea4e02d94c7 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -45,6 +45,7 @@ enum TypeKind FLOAT, USIZE, ISIZE, + NEVER, // there are more to add... ERROR }; @@ -1217,6 +1218,41 @@ class StrType : public BaseType BaseType *clone () final override; }; +// https://doc.rust-lang.org/std/primitive.never.html +// +// Since the `!` type is really complicated and it is even still unstable +// in rustc, only fairly limited support for this type is introduced here. +// Unification between `!` and ANY other type (including ``) is simply +// not allowed. If it is needed, it should be handled manually. For example, +// unifying `!` with other types is very necessary when resolving types of +// `if/else` expressions. +// +// See related discussion at https://github.com/Rust-GCC/gccrs/pull/364 +class NeverType : public BaseType +{ +public: + NeverType (HirId ref, std::set refs = std::set ()) + : BaseType (ref, ref, TypeKind::NEVER, refs) + {} + + NeverType (HirId ref, HirId ty_ref, std::set refs = std::set ()) + : BaseType (ref, ty_ref, TypeKind::NEVER, refs) + {} + + void accept_vis (TyVisitor &vis) override; + + std::string as_string () const override; + + BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; + + BaseType *clone () final override; + + std::string get_name () const override final { return as_string (); } + + bool is_unit () const override { return true; } +}; + class TypeKindFormat { public: @@ -1272,6 +1308,9 @@ class TypeKindFormat case TypeKind::ISIZE: return "Isize"; + case TypeKind::NEVER: + return "Never"; + case TypeKind::ERROR: return "ERROR"; } diff --git a/gcc/testsuite/rust.test/compile/block_expr4.rs b/gcc/testsuite/rust.test/compile/block_expr4.rs index da033ef9ef4e..7e164a949bbf 100644 --- a/gcc/testsuite/rust.test/compile/block_expr4.rs +++ b/gcc/testsuite/rust.test/compile/block_expr4.rs @@ -1,8 +1,40 @@ -fn foo() -> isize { +fn foo() -> i32 { 0 } +fn bar() -> i32 { + foo(); + foo() +} + +fn baz() -> i32 { + { + bar(); + bar(); + } + { + bar(); + bar() + }; + { + bar(); + bar() + } +} + +fn test(ok: i32) -> i32 { + if ok >= 1 { + foo() + } else if ok <= -1 { + bar() + } else { + baz() + } +} + fn main() { let a = foo(); - // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = bar(); + let c = baz(); + test(a + b + c); } diff --git a/gcc/testsuite/rust.test/compile/unused.rs b/gcc/testsuite/rust.test/compile/unused.rs index a4987b5a3b19..0564aa1854ba 100644 --- a/gcc/testsuite/rust.test/compile/unused.rs +++ b/gcc/testsuite/rust.test/compile/unused.rs @@ -14,4 +14,4 @@ fn f() { fn main() { f(); -} \ No newline at end of file +} diff --git a/gcc/testsuite/rust.test/xfail_compile/break1.rs b/gcc/testsuite/rust.test/xfail_compile/break1.rs index be3c9e8ee68b..33053cf5fbca 100644 --- a/gcc/testsuite/rust.test/xfail_compile/break1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/break1.rs @@ -1,7 +1,6 @@ -// { dg-excess-errors "Noisy error and debug" } -fn main() { // { dg-error "expected .... got .." } +fn main() { let a; a = 1; - break a; // { dg-error "cannot `break` outside of a loop" + break a; // { dg-error "cannot `break` outside of a loop" } // { dg-error "failed to type resolve expression" "" { target { *-*-* } } .-1 } } diff --git a/gcc/testsuite/rust.test/xfail_compile/continue1.rs b/gcc/testsuite/rust.test/xfail_compile/continue1.rs index f6314ca6ac71..7b34c2836a83 100644 --- a/gcc/testsuite/rust.test/xfail_compile/continue1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/continue1.rs @@ -5,6 +5,6 @@ fn main() { let _fib = { continue; // { dg-error "cannot `continue` outside of a loop" } // { dg-error "failed to type resolve expression" "" { target { *-*-* } } .-1 } - 123 + 123 // { dg-warning "unreachable expression" } }; } diff --git a/gcc/testsuite/rust.test/xfail_compile/func1.rs b/gcc/testsuite/rust.test/xfail_compile/func1.rs index 7c1ce52fc86f..6758a3898e30 100644 --- a/gcc/testsuite/rust.test/xfail_compile/func1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/func1.rs @@ -1,4 +1,4 @@ -fn test(x: i32) -> bool { // { dg-error "expected .bool. got ..." } +fn test(x: i32) -> bool { return x + 1; // { dg-error "expected .bool. got .i32." } } diff --git a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs index 37eb562597fc..d27f3fb737da 100644 --- a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs @@ -1,12 +1,21 @@ -// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 } - fn test(x: i32) -> i32 { - if x > 1 { + if x > 1 { // { dg-error "expected .... got .." } 1 } else { 2 } - 3 + + { // { dg-error "expected .... got .." } + 3 + } + + if x > 1 { 1 } else { 2 }; + if x > 1 { 1; } else { 2; } + + { 3; } + { 3 }; + + { 3 } } fn main() { diff --git a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs index 75f4db4db05b..47c35f7c591b 100644 --- a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs +++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs @@ -1,11 +1,18 @@ -// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 } - -fn test(x: i32) -> i32 { +fn test1(x: i32) -> i32 { + // { dg-error "expected .i32. got .bool." "" { target *-*-*} .-1 } return 1; // { dg-warning "unreachable expression" "" { target *-*-* } .+1 } true } +fn test2(x: bool) -> bool { + // { dg-error "expected .bool. got ...." "" { target *-*-*} .-1 } + return x; + // { dg-warning "unreachable expression" "" { target *-*-* } .+1 } + () +} + fn main() { - let a = test(1); + let a = test1(1); + let a = test2(true); } diff --git a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs index 2a64fcf9f485..37b1c62414c5 100644 --- a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs +++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs @@ -1,5 +1,4 @@ -// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 } -fn test(x: i32) -> i32 { +fn test(x: i32) -> i32 { // { dg-error "expected .i32. got ...." } if x > 1 { 1 } diff --git a/gcc/testsuite/rust.test/xfail_compile/never_type_err1.rs b/gcc/testsuite/rust.test/xfail_compile/never_type_err1.rs new file mode 100644 index 000000000000..84e215d14f09 --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/never_type_err1.rs @@ -0,0 +1,23 @@ +fn main() { + let x = 0.0; + let a = { + loop { + let c = if x > 0.0 { + break 3; + } else if x < 0.0 { + x + } else { + return; + }; + if x == 0.0 { + break c; // { dg-error "expected .. got .." } + } else { + continue; + } + return; // { dg-warning "unreachable statement" } + } + }; + + let a = 1 + return; // { dg-error "cannot apply this operator to types and !" } + // { dg-error "failed to type resolve expression" "" { target { *-*-* } } .-1 } +} diff --git a/gcc/testsuite/rust.test/xfail_compile/never_type_err2.rs b/gcc/testsuite/rust.test/xfail_compile/never_type_err2.rs new file mode 100644 index 000000000000..c94cb828071f --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/never_type_err2.rs @@ -0,0 +1,4 @@ +// FIXME: Unimplemented features +fn foo() -> ! { // { dg-error "unresolved type" } + let a: !; // { dg-error "unresolved type" } +} diff --git a/gcc/testsuite/rust.test/xfail_compile/never_type_err3.rs b/gcc/testsuite/rust.test/xfail_compile/never_type_err3.rs new file mode 100644 index 000000000000..d1bb0ed262cd --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/never_type_err3.rs @@ -0,0 +1,61 @@ +fn foo() -> i32 { + let c; + let d; + + c = if false { + return 1; + } else { + 0.0 + }; + + d = if true { + 0.0; + } else { + return 1; + }; + + 0 +} + +fn bar() -> i32 { + let a; + let b; + + // FIXME: Unimplemented features + a = if true { // { dg-error "expected .T.. got .!." } + // { dg-error "type resolution failure in AssignmentExpr" "" { target { *-*-* } } .-1 } + return 0; + } else { + return 0; + }; + + // FIXME: Unimplemented features + b = return 0; // { dg-error "expected .T.. got .!." } + // { dg-error "type resolution failure in AssignmentExpr" "" { target { *-*-* } } .-1 } + // { dg-warning "unreachable statement" "" { target { *-*-* } } .-2 } +} + +fn baz() -> i32 { + let mut x = (1.0, return 1, 2.0); + + x.1 = return 2; + // { dg-warning "unreachable statement" "" { target { *-*-* } } .-1 } + + x.1 = 3; // { dg-error "expected .!. got .." } + // { dg-error "type resolution failure in AssignmentExpr" "" { target { *-*-* } } .-1 } + // { dg-warning "unreachable statement" "" { target { *-*-* } } .-2 } + + x.0 = -1.0; + // { dg-warning "unreachable statement" "" { target { *-*-* } } .-1 } + + // FIXME: Unimplemented features + x.0 = return -1; // { dg-error "expected .. got .!." } + // { dg-error "type resolution failure in AssignmentExpr" "" { target { *-*-* } } .-1 } + // { dg-warning "unreachable statement" "" { target { *-*-* } } .-2 } +} + +fn main() { + foo(); + bar(); + baz(); +}