aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-01-06 18:18:42 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-01-08 11:36:54 +0000
commit4e0189ed288223f8b376eedd286f5bdff5b35698 (patch)
tree89ab8d6db72bc19028d9ecb3a1946e8c0aa01ebd
parent290fc4f416c94a86aa5e3d22b785890a12686972 (diff)
downloadgcc-4e0189ed288223f8b376eedd286f5bdff5b35698.zip
gcc-4e0189ed288223f8b376eedd286f5bdff5b35698.tar.gz
gcc-4e0189ed288223f8b376eedd286f5bdff5b35698.tar.bz2
Implicit Returns support.
For implict returns we must consider cases with a block having multiple returns: HIR::BlockExpr Stmts { ... return x } HIR::BlockExpr final_expression { x + 1 } Although the code above is bad this is valid rust code and the rust compiler correctly identifies the final_expression as unreachable. This dead code eliminiation is done as part of AST to HIR lowering. Type resolution examines all blocks to identifiy if they terminate a function with a return/final expression it must correspond accordngly. If the block is the final block the resulting termination of the block must match the return type of the function, else the block must conform to unit type.
-rw-r--r--gcc/rust/ast/rust-expr.h2
-rw-r--r--gcc/rust/ast/rust-stmt.h2
-rw-r--r--gcc/rust/backend/rust-compile-item.h17
-rw-r--r--gcc/rust/backend/rust-compile.cc17
-rw-r--r--gcc/rust/hir/rust-ast-lower-block.h32
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h23
-rw-r--r--gcc/rust/hir/rust-ast-lower-item.h7
-rw-r--r--gcc/rust/hir/rust-ast-lower-stmt.h18
-rw-r--r--gcc/rust/hir/rust-ast-lower.cc67
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h4
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h48
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.h20
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h19
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc36
-rw-r--r--gcc/rust/typecheck/rust-tyty-resolver.h8
-rw-r--r--gcc/rust/typecheck/rust-tyty-rules.h80
-rw-r--r--gcc/rust/typecheck/rust-tyty.h2
-rw-r--r--gcc/testsuite/rust.test/compilable/deadcode1.rs18
-rw-r--r--gcc/testsuite/rust.test/compilable/implicit_returns1.rs65
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/missing_return1.rs5
21 files changed, 387 insertions, 105 deletions
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 8baf7b7..2dbaec8 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -2838,6 +2838,8 @@ public:
}
}
+ size_t num_statements () const { return statements.size (); }
+
// TODO: this mutable getter seems really dodgy. Think up better way.
const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h
index c2ce387..c840112 100644
--- a/gcc/rust/ast/rust-stmt.h
+++ b/gcc/rust/ast/rust-stmt.h
@@ -184,6 +184,8 @@ class ExprStmt : public Stmt
Location locus;
public:
+ Location get_locus_slow () const final override { return get_locus (); }
+
Location get_locus () const { return locus; }
protected:
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index 90630bb..f1b39da 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -232,6 +232,23 @@ public:
return true;
});
+ if (function_body->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 (function_body->expr.get (), ctx);
+ rust_assert (compiled_expr != nullptr);
+
+ auto fncontext = ctx->peek_fn ();
+
+ std::vector<Bexpression *> retstmts;
+ retstmts.push_back (compiled_expr);
+ auto s = ctx->get_backend ()->return_statement (
+ fncontext.fndecl, retstmts, function_body->expr->get_locus_slow ());
+ ctx->add_statement (s);
+ }
+
ctx->pop_block ();
auto body = ctx->get_backend ()->block_statement (code_block);
if (!ctx->get_backend ()->function_set_body (fndecl, body))
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 24b45ee..a52f183 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -90,6 +90,23 @@ CompileBlock::visit (HIR::BlockExpr &expr)
return true;
});
+ 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);
+ rust_assert (compiled_expr != nullptr);
+
+ auto fncontext = ctx->peek_fn ();
+
+ std::vector<Bexpression *> retstmts;
+ retstmts.push_back (compiled_expr);
+ auto s
+ = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts,
+ expr.expr->get_locus_slow ());
+ ctx->add_statement (s);
+ }
+
ctx->pop_block ();
translated = new_block;
}
diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h
index 11f1ab8..1ef581e 100644
--- a/gcc/rust/hir/rust-ast-lower-block.h
+++ b/gcc/rust/hir/rust-ast-lower-block.h
@@ -28,7 +28,7 @@ namespace HIR {
class ASTLoweringBlock : public ASTLoweringBase
{
public:
- static HIR::BlockExpr *translate (AST::BlockExpr *expr)
+ static HIR::BlockExpr *translate (AST::BlockExpr *expr, bool *terminated)
{
ASTLoweringBlock resolver;
expr->accept_vis (resolver);
@@ -40,6 +40,7 @@ public:
resolver.translated);
}
+ *terminated = resolver.terminated;
return resolver.translated;
}
@@ -48,15 +49,18 @@ public:
void visit (AST::BlockExpr &expr);
private:
- ASTLoweringBlock () : ASTLoweringBase (), translated (nullptr) {}
+ ASTLoweringBlock ()
+ : ASTLoweringBase (), translated (nullptr), terminated (false)
+ {}
HIR::BlockExpr *translated;
+ bool terminated;
};
class ASTLoweringIfBlock : public ASTLoweringBase
{
public:
- static HIR::IfExpr *translate (AST::IfExpr *expr)
+ static HIR::IfExpr *translate (AST::IfExpr *expr, bool *terminated)
{
ASTLoweringIfBlock resolver;
expr->accept_vis (resolver);
@@ -67,7 +71,7 @@ public:
resolver.translated->get_mappings ().get_hirid (),
resolver.translated);
}
-
+ *terminated = resolver.terminated;
return resolver.translated;
}
@@ -80,15 +84,19 @@ public:
void visit (AST::IfExprConseqIf &expr);
private:
- ASTLoweringIfBlock () : ASTLoweringBase (), translated (nullptr) {}
+ ASTLoweringIfBlock ()
+ : ASTLoweringBase (), translated (nullptr), terminated (false)
+ {}
HIR::IfExpr *translated;
+ bool terminated;
};
class ASTLoweringExprWithBlock : public ASTLoweringBase
{
public:
- static HIR::ExprWithBlock *translate (AST::ExprWithBlock *expr)
+ static HIR::ExprWithBlock *translate (AST::ExprWithBlock *expr,
+ bool *terminated)
{
ASTLoweringExprWithBlock resolver;
expr->accept_vis (resolver);
@@ -100,6 +108,7 @@ public:
resolver.translated);
}
+ *terminated = resolver.terminated;
return resolver.translated;
}
@@ -107,23 +116,26 @@ public:
void visit (AST::IfExpr &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
void visit (AST::IfExprConseqElse &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
void visit (AST::IfExprConseqIf &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
private:
- ASTLoweringExprWithBlock () : ASTLoweringBase (), translated (nullptr) {}
+ ASTLoweringExprWithBlock ()
+ : ASTLoweringBase (), translated (nullptr), terminated (false)
+ {}
HIR::ExprWithBlock *translated;
+ bool terminated;
};
} // namespace HIR
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
index 87ba0dc..51bf108 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -107,7 +107,7 @@ private:
class ASTLoweringExpr : public ASTLoweringBase
{
public:
- static HIR::Expr *translate (AST::Expr *expr)
+ static HIR::Expr *translate (AST::Expr *expr, bool *terminated = nullptr)
{
ASTLoweringExpr resolver;
expr->accept_vis (resolver);
@@ -121,6 +121,13 @@ public:
resolver.mappings->insert_hir_expr (
resolver.translated->get_mappings ().get_crate_num (),
resolver.translated->get_mappings ().get_hirid (), resolver.translated);
+ resolver.mappings->insert_location (
+ resolver.translated->get_mappings ().get_crate_num (),
+ resolver.translated->get_mappings ().get_hirid (),
+ expr->get_locus_slow ());
+
+ if (terminated != nullptr)
+ *terminated = resolver.terminated;
return resolver.translated;
}
@@ -129,22 +136,22 @@ public:
void visit (AST::IfExpr &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
void visit (AST::IfExprConseqElse &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
void visit (AST::IfExprConseqIf &expr)
{
- translated = ASTLoweringIfBlock::translate (&expr);
+ translated = ASTLoweringIfBlock::translate (&expr, &terminated);
}
void visit (AST::BlockExpr &expr)
{
- translated = ASTLoweringBlock::translate (&expr);
+ translated = ASTLoweringBlock::translate (&expr, &terminated);
}
void visit (AST::PathInExpression &expr)
@@ -154,6 +161,7 @@ public:
void visit (AST::ReturnExpr &expr)
{
+ terminated = true;
HIR::Expr *return_expr
= expr.has_returned_expr ()
? ASTLoweringExpr::translate (expr.get_returned_expr ().get ())
@@ -498,10 +506,13 @@ public:
}
private:
- ASTLoweringExpr () : translated (nullptr), translated_array_elems (nullptr) {}
+ ASTLoweringExpr ()
+ : translated (nullptr), translated_array_elems (nullptr), terminated (false)
+ {}
HIR::Expr *translated;
HIR::ArrayElems *translated_array_elems;
+ bool terminated;
};
} // namespace HIR
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index 2a17880..4a5a3fe 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -185,9 +185,14 @@ public:
function_params.push_back (hir_param);
}
+ bool terminated = false;
std::unique_ptr<HIR::BlockExpr> function_body
= std::unique_ptr<HIR::BlockExpr> (
- ASTLoweringBlock::translate (function.get_definition ().get ()));
+ ASTLoweringBlock::translate (function.get_definition ().get (),
+ &terminated));
+ if (!terminated && function.has_return_type ())
+ rust_error_at (function.get_definition ()->get_locus (),
+ "missing return");
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, function.get_node_id (),
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index f4ecd8e..b672456 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -33,15 +33,12 @@ namespace HIR {
class ASTLoweringStmt : public ASTLoweringBase
{
public:
- static HIR::Stmt *translate (AST::Stmt *stmt)
+ static HIR::Stmt *translate (AST::Stmt *stmt, bool *terminated)
{
ASTLoweringStmt resolver;
stmt->accept_vis (resolver);
- if (resolver.translated == nullptr)
- {
- printf ("Failing translating: %s\n", stmt->as_string ().c_str ());
- rust_assert (resolver.translated != nullptr);
- }
+ rust_assert (resolver.translated != nullptr);
+ *terminated = resolver.terminated;
return resolver.translated;
}
@@ -50,7 +47,8 @@ public:
void visit (AST::ExprStmtWithBlock &stmt)
{
HIR::ExprWithBlock *expr
- = ASTLoweringExprWithBlock::translate (stmt.get_expr ().get ());
+ = ASTLoweringExprWithBlock::translate (stmt.get_expr ().get (),
+ &terminated);
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (),
@@ -67,7 +65,8 @@ public:
void visit (AST::ExprStmtWithoutBlock &stmt)
{
- HIR::Expr *expr = ASTLoweringExpr::translate (stmt.get_expr ().get ());
+ HIR::Expr *expr
+ = ASTLoweringExpr::translate (stmt.get_expr ().get (), &terminated);
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (),
@@ -110,9 +109,10 @@ public:
}
private:
- ASTLoweringStmt () : translated (nullptr) {}
+ ASTLoweringStmt () : translated (nullptr), terminated (false) {}
HIR::Stmt *translated;
+ bool terminated;
};
} // namespace HIR
diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc
index 8dd8800..4f0d0d0 100644
--- a/gcc/rust/hir/rust-ast-lower.cc
+++ b/gcc/rust/hir/rust-ast-lower.cc
@@ -64,17 +64,44 @@ ASTLowering::go ()
void
ASTLoweringBlock::visit (AST::BlockExpr &expr)
{
- std::vector<std::unique_ptr<HIR::Stmt> > block_stmts;
- std::unique_ptr<HIR::ExprWithoutBlock> block_expr;
std::vector<HIR::Attribute> inner_attribs;
std::vector<HIR::Attribute> outer_attribs;
+ std::vector<std::unique_ptr<HIR::Stmt> > block_stmts;
+ bool block_did_terminate = false;
expr.iterate_stmts ([&] (AST::Stmt *s) mutable -> bool {
- auto translated_stmt = ASTLoweringStmt::translate (s);
+ bool terminated = false;
+ auto translated_stmt = ASTLoweringStmt::translate (s, &terminated);
block_stmts.push_back (std::unique_ptr<HIR::Stmt> (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))
+ rust_warning_at (s->get_locus_slow (), 0, "unreachable statement");
+
return true;
});
+ HIR::ExprWithoutBlock *tail_expr = nullptr;
+ if (expr.has_tail_expr () && !block_did_terminate)
+ {
+ tail_expr = (HIR::ExprWithoutBlock *) ASTLoweringExpr::translate (
+ expr.get_tail_expr ().get ());
+ }
+ else if (expr.has_tail_expr () && block_did_terminate)
+ {
+ // warning unreachable tail expressions
+ rust_warning_at (expr.get_tail_expr ()->get_locus_slow (), 0,
+ "unreachable expression");
+ }
+
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
mappings->get_next_hir_id (crate_num),
@@ -82,17 +109,23 @@ ASTLoweringBlock::visit (AST::BlockExpr &expr)
translated
= new HIR::BlockExpr (mapping, std::move (block_stmts),
- std::move (block_expr), std::move (inner_attribs),
- std::move (outer_attribs), expr.get_locus ());
+ std::unique_ptr<HIR::ExprWithoutBlock> (tail_expr),
+ std::move (inner_attribs), std::move (outer_attribs),
+ expr.get_locus ());
+
+ terminated = block_did_terminate || expr.has_tail_expr ();
}
void
ASTLoweringIfBlock::visit (AST::IfExpr &expr)
{
+ bool ignored_terminated = false;
HIR::Expr *condition
- = ASTLoweringExpr::translate (expr.get_condition_expr ().get ());
+ = ASTLoweringExpr::translate (expr.get_condition_expr ().get (),
+ &ignored_terminated);
HIR::BlockExpr *block
- = ASTLoweringBlock::translate (expr.get_if_block ().get ());
+ = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+ &ignored_terminated);
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
@@ -109,10 +142,18 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr)
{
HIR::Expr *condition
= ASTLoweringExpr::translate (expr.get_condition_expr ().get ());
+
+ bool if_block_terminated = false;
+ bool else_block_termianted = false;
+
HIR::BlockExpr *if_block
- = ASTLoweringBlock::translate (expr.get_if_block ().get ());
+ = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+ &if_block_terminated);
HIR::BlockExpr *else_block
- = ASTLoweringBlock::translate (expr.get_else_block ().get ());
+ = ASTLoweringBlock::translate (expr.get_else_block ().get (),
+ &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 (),
@@ -132,10 +173,14 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr)
{
HIR::Expr *condition
= ASTLoweringExpr::translate (expr.get_condition_expr ().get ());
+
+ bool ignored_terminated = false;
HIR::BlockExpr *block
- = ASTLoweringBlock::translate (expr.get_if_block ().get ());
+ = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+ &ignored_terminated);
HIR::IfExpr *conseq_if_expr
- = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get ());
+ = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get (),
+ &ignored_terminated);
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index dc7ab5a..11be8b6 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -2594,6 +2594,8 @@ public:
}
}
+ bool is_final_stmt (Stmt *stmt) { return statements.back ().get () == stmt; }
+
Location get_closing_locus ()
{
if (statements.size () == 0)
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index c3b2312..c69e433 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -85,6 +85,10 @@ public:
return true;
});
+ if (function.get_definition ()->has_tail_expr ())
+ ResolveExpr::go (function.get_definition ()->get_tail_expr ().get (),
+ function.get_node_id ());
+
resolver->get_name_scope ().pop ();
resolver->get_type_scope ().pop ();
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index a5440c0..29244a6 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -32,9 +32,9 @@ namespace Resolver {
class TypeCheckExpr : public TypeCheckBase
{
public:
- static TyTy::TyBase *Resolve (HIR::Expr *expr)
+ static TyTy::TyBase *Resolve (HIR::Expr *expr, bool is_final_expr = false)
{
- TypeCheckExpr resolver;
+ TypeCheckExpr resolver (is_final_expr);
expr->accept_vis (resolver);
if (resolver.infered != nullptr)
resolver.context->insert_type (expr->get_mappings ().get_hirid (),
@@ -245,13 +245,30 @@ public:
{
TypeCheckExpr::Resolve (expr.get_if_condition ());
TypeCheckExpr::Resolve (expr.get_if_block ());
+
+ // if without else always resolves to unit type
+ infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ());
}
void visit (HIR::IfExprConseqElse &expr)
{
- TypeCheckExpr::Resolve (expr.get_if_condition ());
- TypeCheckExpr::Resolve (expr.get_if_block ());
- TypeCheckExpr::Resolve (expr.get_else_block ());
+ // this must combine to what the type is expected
+ // this might be a parameter or the last expr in an if + else in a BlockExpr
+ // then it must resolve to fn return type
+ // else its a unit-type
+ infered = is_final_expr
+ ? context->peek_return_type ()
+ : new TyTy::UnitType (expr.get_mappings ().get_hirid ());
+
+ TypeCheckExpr::Resolve (expr.get_if_condition (), is_final_expr);
+ auto if_blk_ty = TypeCheckExpr::Resolve (expr.get_if_block ());
+ auto else_blk_ty = TypeCheckExpr::Resolve (expr.get_else_block ());
+
+ if (is_final_expr)
+ {
+ infered = infered->combine (if_blk_ty);
+ infered = infered->combine (else_blk_ty);
+ }
}
void visit (HIR::IfExprConseqIf &expr)
@@ -259,22 +276,28 @@ public:
TypeCheckExpr::Resolve (expr.get_if_condition ());
TypeCheckExpr::Resolve (expr.get_if_block ());
TypeCheckExpr::Resolve (expr.get_conseq_if_expr ());
+
+ infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ());
}
void visit (HIR::BlockExpr &expr);
void visit (HIR::ArrayIndexExpr &expr)
{
- // check the index
+ // FIXME this should be size type
TyTy::IntType size_ty (expr.get_index_expr ()->get_mappings ().get_hirid (),
TyTy::IntType::I32);
auto resolved
= size_ty.combine (TypeCheckExpr::Resolve (expr.get_index_expr ()));
- context->insert_type (expr.get_index_expr ()->get_mappings ().get_hirid (),
- resolved);
+ rust_assert (resolved != nullptr);
expr.get_array_expr ()->accept_vis (*this);
- rust_assert (infered != nullptr);
+ if (infered->get_kind () != TyTy::TypeKind::ARRAY)
+ {
+ rust_fatal_error (expr.get_array_expr ()->get_locus_slow (),
+ "expected an ArrayType for index expression");
+ return;
+ }
// extract the element type out now from the base type
infered = TyTyExtractorArray::ExtractElementTypeFromArray (infered);
@@ -318,12 +341,15 @@ public:
}
private:
- TypeCheckExpr ()
- : TypeCheckBase (), infered (nullptr), infered_array_elems (nullptr)
+ TypeCheckExpr (bool is_final_expr)
+ : TypeCheckBase (), infered (nullptr), infered_array_elems (nullptr),
+ is_final_expr (is_final_expr)
{}
TyTy::TyBase *infered;
TyTy::TyBase *infered_array_elems;
+
+ bool is_final_expr;
};
} // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h
index c90af13..adf842c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -72,25 +72,7 @@ public:
ResolveFnType resolve_fn_type (fnType);
context->push_return_type (resolve_fn_type.go ());
- // walk statements to make sure they are all typed correctly and they match
- // up
- function.function_body->iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool {
- TypeCheckStmt::Resolve (s);
- return true;
- });
-
- // now that the stmts have been resolved we must resolve the block of locals
- // and make sure the variables have been resolved
- auto body_mappings = function.function_body->get_mappings ();
- Rib *rib = nullptr;
- if (!resolver->find_name_rib (body_mappings.get_nodeid (), &rib))
- {
- rust_fatal_error (function.get_locus (),
- "failed to lookup locals per block");
- return;
- }
-
- TyTyResolver::Resolve (rib, mappings, resolver, context);
+ TypeCheckExpr::Resolve (function.function_body.get ());
context->pop_return_type ();
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index dbf6583..bf754db 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -30,27 +30,29 @@ namespace Resolver {
class TypeCheckStmt : public TypeCheckBase
{
public:
- static void Resolve (HIR::Stmt *stmt)
+ static TyTy::TyBase *Resolve (HIR::Stmt *stmt, bool is_final_stmt)
{
- TypeCheckStmt resolver;
+ TypeCheckStmt resolver (is_final_stmt);
stmt->accept_vis (resolver);
+ return resolver.infered;
}
void visit (HIR::ExprStmtWithBlock &stmt)
{
- TypeCheckExpr::Resolve (stmt.get_expr ());
+ infered = TypeCheckExpr::Resolve (stmt.get_expr (), is_final_stmt);
}
void visit (HIR::ExprStmtWithoutBlock &stmt)
{
- TypeCheckExpr::Resolve (stmt.get_expr ());
+ infered = TypeCheckExpr::Resolve (stmt.get_expr (), is_final_stmt);
}
void visit (HIR::LetStmt &stmt)
{
TyTy::TyBase *init_expr_ty = nullptr;
if (stmt.has_init_expr ())
- init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
+ init_expr_ty
+ = TypeCheckExpr::Resolve (stmt.get_init_expr (), is_final_stmt);
TyTy::TyBase *specified_ty = nullptr;
if (stmt.has_type ())
@@ -94,7 +96,12 @@ public:
}
private:
- TypeCheckStmt () : TypeCheckBase () {}
+ TypeCheckStmt (bool is_final_stmt)
+ : TypeCheckBase (), is_final_stmt (is_final_stmt)
+ {}
+
+ TyTy::TyBase *infered;
+ bool is_final_stmt;
}; // namespace Resolver
} // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index e7d3366..e68ba9a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -40,10 +40,44 @@ TypeResolution::Resolve (HIR::Crate &crate)
void
TypeCheckExpr::visit (HIR::BlockExpr &expr)
{
+ TyTy::TyBase *block_tyty
+ = new TyTy::UnitType (expr.get_mappings ().get_hirid ());
+
expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool {
- TypeCheckStmt::Resolve (s);
+ bool is_final_stmt = expr.is_final_stmt (s);
+ bool is_final_expr = is_final_stmt && !expr.has_expr ();
+
+ auto infered = TypeCheckStmt::Resolve (s, is_final_stmt);
+ if (is_final_expr)
+ {
+ delete block_tyty;
+ block_tyty = infered;
+ }
+
return true;
});
+
+ if (expr.has_expr ())
+ {
+ auto tail_tyty = TypeCheckExpr::Resolve (expr.expr.get (), true);
+
+ delete block_tyty;
+ block_tyty = tail_tyty;
+ }
+
+ // now that the stmts have been resolved we must resolve the block of locals
+ // and make sure the variables have been resolved
+ auto body_mappings = expr.get_mappings ();
+ Rib *rib = nullptr;
+ if (!resolver->find_name_rib (body_mappings.get_nodeid (), &rib))
+ {
+ rust_fatal_error (expr.get_locus (), "failed to lookup locals per block");
+ return;
+ }
+
+ TyTyResolver::Resolve (rib, mappings, resolver, context);
+
+ infered = block_tyty;
}
// RUST_HIR_TYPE_CHECK_STRUCT_FIELD
diff --git a/gcc/rust/typecheck/rust-tyty-resolver.h b/gcc/rust/typecheck/rust-tyty-resolver.h
index 2851a1e..e2678c2 100644
--- a/gcc/rust/typecheck/rust-tyty-resolver.h
+++ b/gcc/rust/typecheck/rust-tyty-resolver.h
@@ -73,8 +73,6 @@ public:
d.parent, &hir_node_ref);
rust_assert (ok);
- printf ("failed lets try [%u]\n", hir_node_ref);
-
if (!context->lookup_type (hir_node_ref, &resolved))
{
rust_fatal_error (
@@ -102,10 +100,8 @@ public:
&resolved_type);
rust_assert (ok);
- if (!resolved_type->is_unit ())
- {
- return true;
- }
+ if (resolved_type->get_kind () != TyTy::TypeKind::INFER)
+ return true;
auto resolved_tyty = resolved_type;
for (auto it : gathered_types)
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
index 615ef80..46ba633 100644
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -34,58 +34,83 @@ public:
virtual void visit (UnitType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
+ }
+
+ virtual void visit (ADTType &type) override
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (InferType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (FnType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (ParamType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (ArrayType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (BoolType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (IntType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
virtual void visit (UintType &type) override
{
- Location locus = mappings->lookup_location (type.get_ref ());
- rust_error_at (locus, "expected [%s] got [%s]", base->as_string ().c_str (),
- type.as_string ().c_str ());
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location def_locus = mappings->lookup_location (base->get_ref ());
+ rust_error_at (ref_locus, "expected [%s] got [%s]",
+ base->as_string ().c_str (), type.as_string ().c_str ());
+ rust_fatal_error (def_locus, "declared here");
}
protected:
@@ -114,6 +139,11 @@ public:
// we are an inference variable so this means we can take the other as the
// type
+ virtual void visit (UnitType &type) override
+ {
+ resolved = new UnitType (type.get_ref ());
+ }
+
virtual void visit (BoolType &type) override
{
resolved = new BoolType (type.get_ref ());
@@ -165,6 +195,8 @@ public:
return resolved;
}
+ void visit (IntType &type) override { rust_assert (false); }
+
private:
UnitType *base;
TyBase *resolved;
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 59c4bcb..c7c609e 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -49,7 +49,7 @@ class TyVisitor;
class TyBase
{
public:
- ~TyBase () {}
+ virtual ~TyBase () {}
HirId get_ref () const { return ref; }
diff --git a/gcc/testsuite/rust.test/compilable/deadcode1.rs b/gcc/testsuite/rust.test/compilable/deadcode1.rs
new file mode 100644
index 0000000..ec6e240
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/deadcode1.rs
@@ -0,0 +1,18 @@
+fn test1() -> i32 {
+ return 2;
+ 1
+}
+
+fn test2(x: i32) -> i32 {
+ if x > 1 {
+ return 5;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+fn main() {
+ let call1 = test1();
+ let call2 = test2(2);
+}
diff --git a/gcc/testsuite/rust.test/compilable/implicit_returns1.rs b/gcc/testsuite/rust.test/compilable/implicit_returns1.rs
new file mode 100644
index 0000000..49457c6
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/implicit_returns1.rs
@@ -0,0 +1,65 @@
+fn test1() -> i32 {
+ 1
+}
+
+fn test2() -> i32 {
+ return 2;
+}
+
+fn test3(x: i32) -> i32 {
+ if x > 1 {
+ 5
+ } else {
+ 0
+ }
+}
+
+fn test4(x: i32) -> i32 {
+ if x > 1 {
+ return 1;
+ }
+ 0
+}
+
+fn test5(x: i32) -> i32 {
+ if x > 1 {
+ if x == 5 {
+ 7
+ } else {
+ 9
+ }
+ } else {
+ 0
+ }
+}
+
+fn test6(x: i32) -> i32 {
+ if x > 1 {
+ return 5;
+ } else {
+ return 0;
+ }
+}
+
+fn test7(x: i32) -> i32 {
+ if x > 1 {
+ return 5;
+ } else {
+ return 0;
+ }
+}
+
+fn test8() -> i32 {
+ return 1;
+}
+
+fn main() {
+ let call1 = test1();
+ let call2 = test2();
+ let call3 = test3(3);
+ let call4 = test4(4);
+ let call5 = test5(5);
+ let call6 = test6(6);
+ let call7 = test7(7);
+ let call8 = test8();
+}
diff --git a/gcc/testsuite/rust.test/fail_compilation/missing_return1.rs b/gcc/testsuite/rust.test/fail_compilation/missing_return1.rs
new file mode 100644
index 0000000..500d007
--- /dev/null
+++ b/gcc/testsuite/rust.test/fail_compilation/missing_return1.rs
@@ -0,0 +1,5 @@
+fn test1() -> i32 {}
+
+fn main() {
+ let call1 = test1();
+}