aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-23 09:13:59 +0000
committerGitHub <noreply@github.com>2021-04-23 09:13:59 +0000
commitde9af784e79926d01e8c030e999becc4b8bfad0f (patch)
treeeec0947af5d1e9bcbddb29c3b1935136d1948e98
parentdd3c58b2ce55ce6585916607927c3bca087610c6 (diff)
parent28895c1265e19a3e854040610d8478cfb8768d0a (diff)
downloadgcc-de9af784e79926d01e8c030e999becc4b8bfad0f.zip
gcc-de9af784e79926d01e8c030e999becc4b8bfad0f.tar.gz
gcc-de9af784e79926d01e8c030e999becc4b8bfad0f.tar.bz2
Merge #380
380: Fix issues about block expression evaluation r=philberty a=lrh2000 I've tried my best to split https://github.com/Rust-GCC/gccrs/pull/364. Its core part is here. All unrelated fixes should have been removed and I will make them separate PRs, but this PR still has to contain 2 commits and introduce limited support for the never type. https://github.com/Rust-GCC/gccrs/blob/935aff52a66a70e1e96f0a6aa7e0ad37eda3f93c/gcc/testsuite/rust.test/compile/deadcode1.rs#L7-L15 https://github.com/Rust-GCC/gccrs/blob/935aff52a66a70e1e96f0a6aa7e0ad37eda3f93c/gcc/testsuite/rust.test/compile/implicit_returns1.rs#L44-L50 The reason is that the above two tests failed to pass simultaneously after the first commit. The first test requires the `if/else` expression resolves to `()` but the second test requires the `if/else` expression resolves to `<integer>`. They are conflicted. I wonder whether or not this PR is OK, and anyway thanks for your review. Co-authored-by: lrh2000 <lrh2000@pku.edu.cn>
-rw-r--r--gcc/rust/ast/rust-expr.h10
-rw-r--r--gcc/rust/ast/rust-stmt.h9
-rw-r--r--gcc/rust/backend/rust-compile-context.h5
-rw-r--r--gcc/rust/backend/rust-compile-tyty.h5
-rw-r--r--gcc/rust/backend/rust-compile.cc9
-rw-r--r--gcc/rust/hir/rust-ast-lower-stmt.h3
-rw-r--r--gcc/rust/hir/rust-ast-lower.cc2
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h12
-rw-r--r--gcc/rust/hir/tree/rust-hir-stmt.h9
-rw-r--r--gcc/rust/hir/tree/rust-hir.h2
-rw-r--r--gcc/rust/parse/rust-parse-impl.h61
-rw-r--r--gcc/rust/parse/rust-parse.h14
-rw-r--r--gcc/rust/typecheck/rust-hir-const-fold.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h38
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc33
-rw-r--r--gcc/rust/typecheck/rust-substitution-mapper.h4
-rw-r--r--gcc/rust/typecheck/rust-tycheck-dump.h2
-rw-r--r--gcc/rust/typecheck/rust-tyty-call.h2
-rw-r--r--gcc/rust/typecheck/rust-tyty-cmp.h17
-rw-r--r--gcc/rust/typecheck/rust-tyty-rules.h23
-rw-r--r--gcc/rust/typecheck/rust-tyty-visitor.h1
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc32
-rw-r--r--gcc/rust/typecheck/rust-tyty.h39
-rw-r--r--gcc/testsuite/rust.test/compile/block_expr5.rs40
-rw-r--r--gcc/testsuite/rust.test/compile/func1.rs7
-rw-r--r--gcc/testsuite/rust.test/compile/func2.rs20
-rw-r--r--gcc/testsuite/rust.test/compile/never_type1.rs22
-rw-r--r--gcc/testsuite/rust.test/compile/stmt_with_block1.rs13
-rw-r--r--gcc/testsuite/rust.test/compile/unused.rs2
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/break1.rs5
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/func1.rs2
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/func4.rs6
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/func5.rs7
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs4
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs3
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs3
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/implicit_returns_err4.rs10
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/never_type_err1.rs14
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/never_type_err2.rs4
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/stmt_with_block_err1.rs17
-rw-r--r--gcc/testsuite/rust.test/xfail_compile/unsafe.rs1
42 files changed, 421 insertions, 96 deletions
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index dde833f..eb56b65 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<Attribute> outer_attrs;
std::vector<Attribute> inner_attrs;
std::vector<std::unique_ptr<Stmt> > statements;
- std::unique_ptr<ExprWithoutBlock> expr;
+ std::unique_ptr<Expr> expr;
Location locus;
bool marked_for_strip = false;
@@ -2842,7 +2842,7 @@ public:
bool has_tail_expr () const { return expr != nullptr; }
BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements,
- std::unique_ptr<ExprWithoutBlock> block_expr,
+ std::unique_ptr<Expr> block_expr,
std::vector<Attribute> inner_attribs,
std::vector<Attribute> outer_attribs, Location locus)
: outer_attrs (std::move (outer_attribs)),
@@ -2859,7 +2859,7 @@ public:
{
// 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 @@ public:
// 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 @@ public:
std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; }
// TODO: is this better? Or is a "vis_block" better?
- std::unique_ptr<ExprWithoutBlock> &get_tail_expr ()
+ std::unique_ptr<Expr> &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 c840112..7294677 100644
--- a/gcc/rust/ast/rust-stmt.h
+++ b/gcc/rust/ast/rust-stmt.h
@@ -269,14 +269,17 @@ protected:
class ExprStmtWithBlock : public ExprStmt
{
std::unique_ptr<ExprWithBlock> expr;
+ bool semicolon_followed;
public:
std::string as_string () const override;
std::vector<LetStmt *> locals;
- ExprStmtWithBlock (std::unique_ptr<ExprWithBlock> expr, Location locus)
- : ExprStmt (locus), expr (std::move (expr))
+ ExprStmtWithBlock (std::unique_ptr<ExprWithBlock> expr, Location locus,
+ bool semicolon_followed)
+ : ExprStmt (locus), expr (std::move (expr)),
+ semicolon_followed (semicolon_followed)
{}
// Copy constructor with clone
@@ -318,6 +321,8 @@ public:
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-context.h b/gcc/rust/backend/rust-compile-context.h
index 226cec6..11e791c 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -501,6 +501,11 @@ public:
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-tyty.h b/gcc/rust/backend/rust-compile-tyty.h
index 28db289..ba98ac0 100644
--- a/gcc/rust/backend/rust-compile-tyty.h
+++ b/gcc/rust/backend/rust-compile-tyty.h
@@ -222,6 +222,11 @@ public:
= 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 a2f5247..9375dd0 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -256,7 +256,7 @@ CompileBlock::visit (HIR::BlockExpr &expr)
}
}
- 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
@@ -410,15 +410,14 @@ HIRCompileBase::compile_function_body (
}
}
- if (function_body->has_expr () && function_body->tail_expr_reachable ())
+ 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);
- if (has_return_type)
+ if (has_return_type && compiled_expr)
{
std::vector<Bexpression *> retstmts;
retstmts.push_back (compiled_expr);
@@ -428,7 +427,7 @@ HIRCompileBase::compile_function_body (
function_body->get_final_expr ()->get_locus_slow ());
ctx->add_statement (ret);
}
- else
+ else if (compiled_expr)
{
Bstatement *final_stmt
= ctx->get_backend ()->expression_statement (fndecl, compiled_expr);
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index e15714c..2d3f59d 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -59,7 +59,8 @@ public:
translated
= new HIR::ExprStmtWithBlock (mapping,
std::unique_ptr<HIR::ExprWithBlock> (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);
diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc
index 0bacdd2..86b10d5 100644
--- a/gcc/rust/hir/rust-ast-lower.cc
+++ b/gcc/rust/hir/rust-ast-lower.cc
@@ -90,7 +90,7 @@ ASTLoweringBlock::visit (AST::BlockExpr &expr)
return true;
});
- bool tail_reachable = expr.has_tail_expr () && !block_did_terminate;
+ bool tail_reachable = !block_did_terminate;
if (expr.has_tail_expr () && block_did_terminate)
{
// warning unreachable tail expressions
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 100c527..50f1eb8 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -2489,7 +2489,7 @@ public:
std::vector<Attribute> inner_attrs;
std::vector<std::unique_ptr<Stmt> > statements;
- std::unique_ptr<ExprWithoutBlock> expr; // inlined from Statements
+ std::unique_ptr<Expr> expr; // inlined from Statements
bool tail_reachable;
Location locus;
@@ -2502,11 +2502,11 @@ public:
// 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<std::unique_ptr<Stmt> > block_statements,
- std::unique_ptr<ExprWithoutBlock> block_expr, bool tail_reachable,
+ std::unique_ptr<Expr> block_expr, bool tail_reachable,
std::vector<Attribute> inner_attribs,
std::vector<Attribute> outer_attribs, Location locus)
: ExprWithBlock (std::move (mappings), std::move (outer_attribs)),
@@ -2522,7 +2522,7 @@ public:
{
// 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)
@@ -2534,7 +2534,7 @@ public:
{
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;
@@ -2580,7 +2580,7 @@ public:
return statements[statements.size () - 1]->get_locus_slow ();
}
- std::unique_ptr<ExprWithoutBlock> &get_final_expr () { return expr; }
+ std::unique_ptr<Expr> &get_final_expr () { return expr; }
std::vector<std::unique_ptr<Stmt> > &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 3384aaa..e34fa7e 100644
--- a/gcc/rust/hir/tree/rust-hir-stmt.h
+++ b/gcc/rust/hir/tree/rust-hir-stmt.h
@@ -193,13 +193,16 @@ protected:
class ExprStmtWithBlock : public ExprStmt
{
std::unique_ptr<ExprWithBlock> expr;
+ bool must_be_unit;
public:
std::string as_string () const override;
ExprStmtWithBlock (Analysis::NodeMapping mappings,
- std::unique_ptr<ExprWithBlock> expr, Location locus)
- : ExprStmt (std::move (mappings), locus), expr (std::move (expr))
+ std::unique_ptr<ExprWithBlock> 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 @@ public:
ExprWithBlock *get_expr () { return expr.get (); }
+ bool is_unit_check_needed () const override { return must_be_unit; }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h
index 5198635..9bda63a 100644
--- a/gcc/rust/hir/tree/rust-hir.h
+++ b/gcc/rust/hir/tree/rust-hir.h
@@ -723,6 +723,8 @@ public:
* methods. */
virtual Location get_locus_slow () const { return Location (); }
+ virtual bool is_unit_check_needed () const { return false; }
+
const Analysis::NodeMapping &get_mappings () const { return mappings; }
protected:
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 9697169..6d38ace 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -7022,11 +7022,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt (
}
}
-/* Parses a expression statement containing an expression with block.
- * Disambiguates internally. */
template <typename ManagedTokenSource>
-std::unique_ptr<AST::ExprStmtWithBlock>
-Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
+std::unique_ptr<AST::ExprWithBlock>
+Parser<ManagedTokenSource>::parse_expr_with_block (
std::vector<AST::Attribute> outer_attrs)
{
std::unique_ptr<AST::ExprWithBlock> expr_parsed = nullptr;
@@ -7113,9 +7111,23 @@ Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
return nullptr;
}
+ return expr_parsed;
+}
+
+/* Parses a expression statement containing an expression with block.
+ * Disambiguates internally. */
+template <typename ManagedTokenSource>
+std::unique_ptr<AST::ExprStmtWithBlock>
+Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
+ std::vector<AST::Attribute> 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<AST::ExprStmtWithBlock> (
- 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<ManagedTokenSource>::parse_block_expr (
// parse statements and expression
std::vector<std::unique_ptr<AST::Stmt>> stmts;
- std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr;
+ std::unique_ptr<AST::Expr> expr = nullptr;
const_TokenPtr t = lexer.peek_token ();
while (t->get_id () != RIGHT_CURLY)
@@ -11438,6 +11450,29 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
}
}
+template <typename ManagedTokenSource>
+ExprOrStmt
+Parser<ManagedTokenSource>::parse_stmt_or_expr_with_block (
+ std::vector<AST::Attribute> 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<AST::ExprStmtWithBlock> 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 +11543,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
{
case LEFT_CURLY: {
// unsafe block
- std::unique_ptr<AST::ExprStmtWithBlock> 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 +11610,7 @@ Parser<ManagedTokenSource>::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<AST::ExprStmtWithBlock> 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 +11621,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
&& (t2->get_id () == LOOP || t2->get_id () == WHILE
|| t2->get_id () == FOR))
{
- std::unique_ptr<AST::ExprStmtWithBlock> 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 f6faa96..47f55ea 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<AST::ExprWithoutBlock> expr;
+ std::unique_ptr<AST::Expr> expr;
std::unique_ptr<AST::Stmt> 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<AST::ExprWithoutBlock> expr)
- : expr (std::move (expr))
- {}
+ ExprOrStmt (std::unique_ptr<AST::Expr> expr) : expr (std::move (expr)) {}
// statement constructor
ExprOrStmt (std::unique_ptr<AST::Stmt> 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 @@ private:
ParseRestrictions restrictions = ParseRestrictions ());
// Expression-related (non-Pratt parsed)
+ std::unique_ptr<AST::ExprWithBlock>
+ parse_expr_with_block (std::vector<AST::Attribute> outer_attrs);
std::unique_ptr<AST::ExprWithoutBlock>
parse_expr_without_block (std::vector<AST::Attribute> outer_attrs
= std::vector<AST::Attribute> ());
@@ -592,6 +590,8 @@ private:
parse_expr_stmt_without_block (std::vector<AST::Attribute> outer_attrs);
ExprOrStmt parse_stmt_or_expr_without_block ();
ExprOrStmt
+ parse_stmt_or_expr_with_block (std::vector<AST::Attribute> outer_attrs);
+ ExprOrStmt
parse_macro_invocation_maybe_semi (std::vector<AST::Attribute> outer_attrs);
ExprOrStmt
parse_path_based_stmt_or_expr (std::vector<AST::Attribute> outer_attrs);
diff --git a/gcc/rust/typecheck/rust-hir-const-fold.h b/gcc/rust/typecheck/rust-hir-const-fold.h
index f6cd6ea..4c030c5 100644
--- a/gcc/rust/typecheck/rust-hir-const-fold.h
+++ b/gcc/rust/typecheck/rust-hir-const-fold.h
@@ -183,6 +183,8 @@ public:
= backend->named_type ("str", raw_str, Linemap::predeclared_location ());
}
+ void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+
private:
ConstFoldType (::Backend *backend)
: backend (backend), translated (backend->error_type ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 787b37d..5643ad6 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -146,16 +146,15 @@ public:
void visit (HIR::ReturnExpr &expr) override
{
- if (!expr.has_return_expr ())
- {
- infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ());
- return;
- }
-
auto fn_return_tyty = context->peek_return_type ();
rust_assert (fn_return_tyty != nullptr);
- auto expr_ty = TypeCheckExpr::Resolve (expr.get_expr (), false);
+ TyTy::BaseType *expr_ty;
+ if (expr.has_return_expr ())
+ expr_ty = TypeCheckExpr::Resolve (expr.get_expr (), false);
+ else
+ expr_ty = new TyTy::TupleType (expr.get_mappings ().get_hirid ());
+
if (expr_ty == nullptr)
{
rust_error_at (expr.get_locus (),
@@ -167,6 +166,8 @@ public:
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
@@ -623,17 +624,28 @@ public:
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;
@@ -962,7 +974,7 @@ public:
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
@@ -974,7 +986,7 @@ public:
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 44fe943..1205dce 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 @@ public:
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.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index 8f635bc..3484eee 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -124,14 +124,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)
{
@@ -139,29 +132,23 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
return false;
}
- if (stmt_is_final_expr)
- {
- delete block_tyty;
- block_tyty = resolved;
- }
- else if (!resolved->is_unit ())
+ if (s->is_unit_check_needed () && !resolved->is_unit ())
{
- rust_error_at (s->get_locus_slow (), "expected () got %s",
- resolved->as_string ().c_str ());
+ auto unit = new TyTy::TupleType (s->get_mappings ().get_hirid ());
+ resolved = unit->unify (resolved);
}
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 cd04b0e..37a82c4 100644
--- a/gcc/rust/typecheck/rust-substitution-mapper.h
+++ b/gcc/rust/typecheck/rust-substitution-mapper.h
@@ -105,6 +105,7 @@ public:
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)
@@ -163,6 +164,7 @@ public:
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)
@@ -217,6 +219,7 @@ public:
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)
@@ -264,6 +267,7 @@ public:
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:
GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {}
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index 953770e..2ab8abb 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -107,7 +107,7 @@ public:
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 4171da5..2aba298 100644
--- a/gcc/rust/typecheck/rust-tyty-call.h
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -53,6 +53,7 @@ public:
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 @@ public:
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 b195e5c..1641264 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -84,6 +84,8 @@ public:
virtual void visit (StrType &) override { ok = false; }
+ virtual void visit (NeverType &) override { ok = false; }
+
protected:
BaseCmp (BaseType *base)
: mappings (Analysis::Mappings::get ()),
@@ -815,6 +817,21 @@ private:
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 c5d2ced..06bb33f 100644
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -296,6 +296,14 @@ public:
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 ()),
@@ -1142,6 +1150,21 @@ private:
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 453a3b6..0ed7eef 100644
--- a/gcc/rust/typecheck/rust-tyty-visitor.h
+++ b/gcc/rust/typecheck/rust-tyty-visitor.h
@@ -44,6 +44,7 @@ public:
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 88743cb..baa997b 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -1316,6 +1316,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 e139bfd..bc4c9c4 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -46,6 +46,7 @@ enum TypeKind
FLOAT,
USIZE,
ISIZE,
+ NEVER,
// there are more to add...
ERROR
};
@@ -1228,6 +1229,41 @@ public:
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 `<T?>`) 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<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::NEVER, refs)
+ {}
+
+ NeverType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : 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:
@@ -1283,6 +1319,9 @@ public:
case TypeKind::ISIZE:
return "Isize";
+ case TypeKind::NEVER:
+ return "Never";
+
case TypeKind::ERROR:
return "ERROR";
}
diff --git a/gcc/testsuite/rust.test/compile/block_expr5.rs b/gcc/testsuite/rust.test/compile/block_expr5.rs
new file mode 100644
index 0000000..7e164a9
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/block_expr5.rs
@@ -0,0 +1,40 @@
+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();
+ let b = bar();
+ let c = baz();
+ test(a + b + c);
+}
diff --git a/gcc/testsuite/rust.test/compile/func1.rs b/gcc/testsuite/rust.test/compile/func1.rs
new file mode 100644
index 0000000..df1789e
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/func1.rs
@@ -0,0 +1,7 @@
+fn not_void() -> i32 {
+ 8
+}
+
+fn main() {
+ not_void();
+}
diff --git a/gcc/testsuite/rust.test/compile/func2.rs b/gcc/testsuite/rust.test/compile/func2.rs
new file mode 100644
index 0000000..f7dd556
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/func2.rs
@@ -0,0 +1,20 @@
+fn foo() {
+ 8;
+ 8;
+}
+
+fn bar() -> i32 {
+ 8;
+ 8
+}
+
+fn baz() -> i32 {
+ 8;
+ return 8;
+}
+
+fn main() {
+ let a = foo(); // { dg-warning "unused name" }
+ let b = bar(); // { dg-warning "unused name" }
+ let c = baz(); // { dg-warning "unused name" }
+}
diff --git a/gcc/testsuite/rust.test/compile/never_type1.rs b/gcc/testsuite/rust.test/compile/never_type1.rs
new file mode 100644
index 0000000..0f15029
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/never_type1.rs
@@ -0,0 +1,22 @@
+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 main() {
+ foo();
+}
diff --git a/gcc/testsuite/rust.test/compile/stmt_with_block1.rs b/gcc/testsuite/rust.test/compile/stmt_with_block1.rs
new file mode 100644
index 0000000..b6aa56c
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/stmt_with_block1.rs
@@ -0,0 +1,13 @@
+fn test(x: i32) -> i32 {
+ if x > 1 { 1 } else { 2 };
+ if x > 1 { 1; } else { 2; }
+
+ { 3; }
+ { 3 };
+
+ { 3 }
+}
+
+fn main() {
+ let a = test(0); // { dg-warning "unused name" }
+}
diff --git a/gcc/testsuite/rust.test/compile/unused.rs b/gcc/testsuite/rust.test/compile/unused.rs
index a4987b5..0564aa1 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 be3c9e8..33053cf 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 .<tyty::error>." }
+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/func1.rs b/gcc/testsuite/rust.test/xfail_compile/func1.rs
index 7c1ce52..6758a38 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 .<tyty::error>.." }
+fn test(x: i32) -> bool {
return x + 1; // { dg-error "expected .bool. got .i32." }
}
diff --git a/gcc/testsuite/rust.test/xfail_compile/func4.rs b/gcc/testsuite/rust.test/xfail_compile/func4.rs
new file mode 100644
index 0000000..3b2d2b0
--- /dev/null
+++ b/gcc/testsuite/rust.test/xfail_compile/func4.rs
@@ -0,0 +1,6 @@
+fn func() -> i32 { // { dg-error "expected .i32. got ...." }
+}
+
+fn main() {
+ func();
+}
diff --git a/gcc/testsuite/rust.test/xfail_compile/func5.rs b/gcc/testsuite/rust.test/xfail_compile/func5.rs
new file mode 100644
index 0000000..05624f5
--- /dev/null
+++ b/gcc/testsuite/rust.test/xfail_compile/func5.rs
@@ -0,0 +1,7 @@
+fn func() -> i32 {
+ return; // { dg-error "expected .i32. got ...." }
+}
+
+fn main() {
+ func();
+}
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 37eb562..973ba80 100644
--- a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs
+++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs
@@ -1,7 +1,5 @@
-// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 }
-
fn test(x: i32) -> i32 {
- if x > 1 {
+ if x > 1 { // { dg-error "expected .... got .<integer>." }
1
} else {
2
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 75f4db4..fb90748 100644
--- a/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs
+++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err2.rs
@@ -1,6 +1,5 @@
-// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 }
-
fn test(x: i32) -> i32 {
+ // { dg-error "expected .i32. got .bool." "" { target *-*-* } .-1 }
return 1;
// { dg-warning "unreachable expression" "" { target *-*-* } .+1 }
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 2a64fcf..37b1c62 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/implicit_returns_err4.rs b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err4.rs
new file mode 100644
index 0000000..59c6a02
--- /dev/null
+++ b/gcc/testsuite/rust.test/xfail_compile/implicit_returns_err4.rs
@@ -0,0 +1,10 @@
+fn test(x: bool) -> bool {
+ // { dg-error "expected .bool. got ...." "" { target *-*-*} .-1 }
+ return x;
+ // { dg-warning "unreachable expression" "" { target *-*-* } .+1 }
+ ()
+}
+
+fn main() {
+ let a = test(true);
+}
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 0000000..52b1283
--- /dev/null
+++ b/gcc/testsuite/rust.test/xfail_compile/never_type_err1.rs
@@ -0,0 +1,14 @@
+fn test() {
+ let a;
+
+ // FIXME: Unimplemented features
+ a = if true { // { dg-error "expected .T.. got .!." }
+ return;
+ } else {
+ return;
+ };
+}
+
+fn main() {
+ test();
+}
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 0000000..c94cb82
--- /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/stmt_with_block_err1.rs b/gcc/testsuite/rust.test/xfail_compile/stmt_with_block_err1.rs
new file mode 100644
index 0000000..8780d0f
--- /dev/null
+++ b/gcc/testsuite/rust.test/xfail_compile/stmt_with_block_err1.rs
@@ -0,0 +1,17 @@
+fn test(x: i32) -> i32 {
+ if x > 1 { // { dg-error "expected .... got .<integer>." }
+ 1
+ } else {
+ 2
+ }
+
+ { // { dg-error "expected .... got .<integer>." }
+ 3
+ }
+
+ 3
+}
+
+fn main() {
+ let a = test(0);
+}
diff --git a/gcc/testsuite/rust.test/xfail_compile/unsafe.rs b/gcc/testsuite/rust.test/xfail_compile/unsafe.rs
index 632be94..d0cb87d 100644
--- a/gcc/testsuite/rust.test/xfail_compile/unsafe.rs
+++ b/gcc/testsuite/rust.test/xfail_compile/unsafe.rs
@@ -1,4 +1,5 @@
fn main() { // { dg-ice "#382" }
unsafe {
}
+ ()
}