Skip to content

Commit c5fdf8c

Browse files
committed
The trailing expression is not necessarily without a block
1 parent 498758a commit c5fdf8c

14 files changed

+105
-50
lines changed

gcc/rust/ast/rust-expr.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2828,7 +2828,7 @@ class BlockExpr : public ExprWithBlock
28282828
std::vector<Attribute> outer_attrs;
28292829
std::vector<Attribute> inner_attrs;
28302830
std::vector<std::unique_ptr<Stmt> > statements;
2831-
std::unique_ptr<ExprWithoutBlock> expr;
2831+
std::unique_ptr<Expr> expr;
28322832
Location locus;
28332833
bool marked_for_strip = false;
28342834

@@ -2842,7 +2842,7 @@ class BlockExpr : public ExprWithBlock
28422842
bool has_tail_expr () const { return expr != nullptr; }
28432843

28442844
BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements,
2845-
std::unique_ptr<ExprWithoutBlock> block_expr,
2845+
std::unique_ptr<Expr> block_expr,
28462846
std::vector<Attribute> inner_attribs,
28472847
std::vector<Attribute> outer_attribs, Location locus)
28482848
: outer_attrs (std::move (outer_attribs)),
@@ -2859,7 +2859,7 @@ class BlockExpr : public ExprWithBlock
28592859
{
28602860
// guard to protect from null pointer dereference
28612861
if (other.expr != nullptr)
2862-
expr = other.expr->clone_expr_without_block ();
2862+
expr = other.expr->clone_expr ();
28632863

28642864
statements.reserve (other.statements.size ());
28652865
for (const auto &e : other.statements)
@@ -2877,7 +2877,7 @@ class BlockExpr : public ExprWithBlock
28772877

28782878
// guard to protect from null pointer dereference
28792879
if (other.expr != nullptr)
2880-
expr = other.expr->clone_expr_without_block ();
2880+
expr = other.expr->clone_expr ();
28812881
else
28822882
expr = nullptr;
28832883

@@ -2929,7 +2929,7 @@ class BlockExpr : public ExprWithBlock
29292929
std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; }
29302930

29312931
// TODO: is this better? Or is a "vis_block" better?
2932-
std::unique_ptr<ExprWithoutBlock> &get_tail_expr ()
2932+
std::unique_ptr<Expr> &get_tail_expr ()
29332933
{
29342934
rust_assert (has_tail_expr ());
29352935
return expr;

gcc/rust/ast/rust-stmt.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,14 +269,17 @@ class ExprStmtWithoutBlock : public ExprStmt
269269
class ExprStmtWithBlock : public ExprStmt
270270
{
271271
std::unique_ptr<ExprWithBlock> expr;
272+
bool semicolon_followed;
272273

273274
public:
274275
std::string as_string () const override;
275276

276277
std::vector<LetStmt *> locals;
277278

278-
ExprStmtWithBlock (std::unique_ptr<ExprWithBlock> expr, Location locus)
279-
: ExprStmt (locus), expr (std::move (expr))
279+
ExprStmtWithBlock (std::unique_ptr<ExprWithBlock> expr, Location locus,
280+
bool semicolon_followed)
281+
: ExprStmt (locus), expr (std::move (expr)),
282+
semicolon_followed (semicolon_followed)
280283
{}
281284

282285
// Copy constructor with clone
@@ -318,6 +321,8 @@ class ExprStmtWithBlock : public ExprStmt
318321
return expr;
319322
}
320323

324+
bool is_semicolon_followed () const { return semicolon_followed; }
325+
321326
protected:
322327
/* Use covariance to implement clone function as returning this object rather
323328
* than base */

gcc/rust/backend/rust-compile.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,11 @@ HIRCompileBase::compile_function_body (
416416
// dead code elimination should remove any bad trailing expressions
417417
Bexpression *compiled_expr
418418
= CompileExpr::Compile (function_body->expr.get (), ctx);
419-
rust_assert (compiled_expr != nullptr);
420419

421420
if (has_return_type)
422421
{
422+
rust_assert (compiled_expr != nullptr);
423+
423424
std::vector<Bexpression *> retstmts;
424425
retstmts.push_back (compiled_expr);
425426

@@ -428,7 +429,7 @@ HIRCompileBase::compile_function_body (
428429
function_body->get_final_expr ()->get_locus_slow ());
429430
ctx->add_statement (ret);
430431
}
431-
else
432+
else if (compiled_expr)
432433
{
433434
Bstatement *final_stmt
434435
= ctx->get_backend ()->expression_statement (fndecl, compiled_expr);

gcc/rust/hir/rust-ast-lower-stmt.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class ASTLoweringStmt : public ASTLoweringBase
5959
translated
6060
= new HIR::ExprStmtWithBlock (mapping,
6161
std::unique_ptr<HIR::ExprWithBlock> (expr),
62-
stmt.get_locus ());
62+
stmt.get_locus (),
63+
!stmt.is_semicolon_followed ());
6364
mappings->insert_location (crate_num, mapping.get_hirid (),
6465
stmt.get_locus ());
6566
mappings->insert_hir_stmt (crate_num, mapping.get_hirid (), translated);

gcc/rust/hir/tree/rust-hir-expr.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,7 +2498,7 @@ class BlockExpr : public ExprWithBlock
24982498
std::vector<Attribute> inner_attrs;
24992499

25002500
std::vector<std::unique_ptr<Stmt> > statements;
2501-
std::unique_ptr<ExprWithoutBlock> expr; // inlined from Statements
2501+
std::unique_ptr<Expr> expr; // inlined from Statements
25022502

25032503
bool tail_reachable;
25042504
Location locus;
@@ -2515,7 +2515,7 @@ class BlockExpr : public ExprWithBlock
25152515

25162516
BlockExpr (Analysis::NodeMapping mappings,
25172517
std::vector<std::unique_ptr<Stmt> > block_statements,
2518-
std::unique_ptr<ExprWithoutBlock> block_expr, bool tail_reachable,
2518+
std::unique_ptr<Expr> block_expr, bool tail_reachable,
25192519
std::vector<Attribute> inner_attribs,
25202520
std::vector<Attribute> outer_attribs, Location locus)
25212521
: ExprWithBlock (std::move (mappings), std::move (outer_attribs)),
@@ -2531,7 +2531,7 @@ class BlockExpr : public ExprWithBlock
25312531
{
25322532
// guard to protect from null pointer dereference
25332533
if (other.expr != nullptr)
2534-
expr = other.expr->clone_expr_without_block ();
2534+
expr = other.expr->clone_expr ();
25352535

25362536
statements.reserve (other.statements.size ());
25372537
for (const auto &e : other.statements)
@@ -2543,7 +2543,7 @@ class BlockExpr : public ExprWithBlock
25432543
{
25442544
ExprWithBlock::operator= (other);
25452545
// statements = other.statements;
2546-
expr = other.expr->clone_expr_without_block ();
2546+
expr = other.expr->clone_expr ();
25472547
inner_attrs = other.inner_attrs;
25482548
locus = other.locus;
25492549
// outer_attrs = other.outer_attrs;
@@ -2589,7 +2589,7 @@ class BlockExpr : public ExprWithBlock
25892589
return statements[statements.size () - 1]->get_locus_slow ();
25902590
}
25912591

2592-
std::unique_ptr<ExprWithoutBlock> &get_final_expr () { return expr; }
2592+
std::unique_ptr<Expr> &get_final_expr () { return expr; }
25932593

25942594
std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; }
25952595

gcc/rust/hir/tree/rust-hir-stmt.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,16 @@ class ExprStmtWithoutBlock : public ExprStmt
193193
class ExprStmtWithBlock : public ExprStmt
194194
{
195195
std::unique_ptr<ExprWithBlock> expr;
196+
bool must_be_unit;
196197

197198
public:
198199
std::string as_string () const override;
199200

200201
ExprStmtWithBlock (Analysis::NodeMapping mappings,
201-
std::unique_ptr<ExprWithBlock> expr, Location locus)
202-
: ExprStmt (std::move (mappings), locus), expr (std::move (expr))
202+
std::unique_ptr<ExprWithBlock> expr, Location locus,
203+
bool must_be_unit)
204+
: ExprStmt (std::move (mappings), locus), expr (std::move (expr)),
205+
must_be_unit (must_be_unit)
203206
{}
204207

205208
// Copy constructor with clone
@@ -224,6 +227,8 @@ class ExprStmtWithBlock : public ExprStmt
224227

225228
ExprWithBlock *get_expr () { return expr.get (); }
226229

230+
bool is_unit_check_needed () const override { return must_be_unit; }
231+
227232
protected:
228233
/* Use covariance to implement clone function as returning this object rather
229234
* than base */

gcc/rust/hir/tree/rust-hir.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,8 @@ class Stmt
723723
* methods. */
724724
virtual Location get_locus_slow () const { return Location (); }
725725

726+
virtual bool is_unit_check_needed () const { return false; }
727+
726728
const Analysis::NodeMapping &get_mappings () const { return mappings; }
727729

728730
protected:

gcc/rust/parse/rust-parse-impl.h

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7022,11 +7022,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt (
70227022
}
70237023
}
70247024

7025-
/* Parses a expression statement containing an expression with block.
7026-
* Disambiguates internally. */
70277025
template <typename ManagedTokenSource>
7028-
std::unique_ptr<AST::ExprStmtWithBlock>
7029-
Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
7026+
std::unique_ptr<AST::ExprWithBlock>
7027+
Parser<ManagedTokenSource>::parse_expr_with_block (
70307028
std::vector<AST::Attribute> outer_attrs)
70317029
{
70327030
std::unique_ptr<AST::ExprWithBlock> expr_parsed = nullptr;
@@ -7113,9 +7111,23 @@ Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
71137111
return nullptr;
71147112
}
71157113

7114+
return expr_parsed;
7115+
}
7116+
7117+
/* Parses a expression statement containing an expression with block.
7118+
* Disambiguates internally. */
7119+
template <typename ManagedTokenSource>
7120+
std::unique_ptr<AST::ExprStmtWithBlock>
7121+
Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
7122+
std::vector<AST::Attribute> outer_attrs)
7123+
{
7124+
auto expr_parsed = parse_expr_with_block (std::move (outer_attrs));
7125+
auto locus = expr_parsed->get_locus ();
7126+
71167127
// return expr stmt created from expr
71177128
return std::unique_ptr<AST::ExprStmtWithBlock> (
7118-
new AST::ExprStmtWithBlock (std::move (expr_parsed), t->get_locus ()));
7129+
new AST::ExprStmtWithBlock (std::move (expr_parsed), locus,
7130+
lexer.peek_token ()->get_id () == SEMICOLON));
71197131
}
71207132

71217133
/* Parses an expression statement containing an expression without block.
@@ -7286,7 +7298,7 @@ Parser<ManagedTokenSource>::parse_block_expr (
72867298

72877299
// parse statements and expression
72887300
std::vector<std::unique_ptr<AST::Stmt>> stmts;
7289-
std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr;
7301+
std::unique_ptr<AST::Expr> expr = nullptr;
72907302

72917303
const_TokenPtr t = lexer.peek_token ();
72927304
while (t->get_id () != RIGHT_CURLY)
@@ -11438,6 +11450,29 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
1143811450
}
1143911451
}
1144011452

11453+
template <typename ManagedTokenSource>
11454+
ExprOrStmt
11455+
Parser<ManagedTokenSource>::parse_stmt_or_expr_with_block (
11456+
std::vector<AST::Attribute> outer_attrs)
11457+
{
11458+
auto expr = parse_expr_with_block (std::move (outer_attrs));
11459+
auto tok = lexer.peek_token ();
11460+
11461+
// tail expr in a block expr
11462+
if (tok->get_id () == RIGHT_CURLY)
11463+
return ExprOrStmt (std::move (expr));
11464+
11465+
// internal block expr must either have semicolons followed, or evaluate to ()
11466+
auto locus = expr->get_locus_slow ();
11467+
std::unique_ptr<AST::ExprStmtWithBlock> stmt (
11468+
new AST::ExprStmtWithBlock (std::move (expr), locus,
11469+
tok->get_id () == SEMICOLON));
11470+
if (tok->get_id () == SEMICOLON)
11471+
lexer.skip_token ();
11472+
11473+
return ExprOrStmt (std::move (stmt));
11474+
}
11475+
1144111476
/* Parses a statement or expression (depending on whether a trailing semicolon
1144211477
* exists). Useful for block expressions where it cannot be determined through
1144311478
* lookahead whether it is a statement or expression to be parsed. */
@@ -11508,9 +11543,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
1150811543
{
1150911544
case LEFT_CURLY: {
1151011545
// unsafe block
11511-
std::unique_ptr<AST::ExprStmtWithBlock> stmt (
11512-
parse_expr_stmt_with_block (std::move (outer_attrs)));
11513-
return ExprOrStmt (std::move (stmt));
11546+
return parse_stmt_or_expr_with_block (std::move (outer_attrs));
1151411547
}
1151511548
case TRAIT: {
1151611549
// unsafe trait
@@ -11577,11 +11610,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
1157711610
case MATCH_TOK:
1157811611
case LEFT_CURLY:
1157911612
case ASYNC: {
11580-
// all expressions with block, so cannot be final expr without block in
11581-
// function
11582-
std::unique_ptr<AST::ExprStmtWithBlock> stmt (
11583-
parse_expr_stmt_with_block (std::move (outer_attrs)));
11584-
return ExprOrStmt (std::move (stmt));
11613+
return parse_stmt_or_expr_with_block (std::move (outer_attrs));
1158511614
}
1158611615
case LIFETIME: {
1158711616
/* FIXME: are there any expressions without blocks that can have
@@ -11592,9 +11621,7 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
1159211621
&& (t2->get_id () == LOOP || t2->get_id () == WHILE
1159311622
|| t2->get_id () == FOR))
1159411623
{
11595-
std::unique_ptr<AST::ExprStmtWithBlock> stmt (
11596-
parse_expr_stmt_with_block (std::move (outer_attrs)));
11597-
return ExprOrStmt (std::move (stmt));
11624+
return parse_stmt_or_expr_with_block (std::move (outer_attrs));
1159811625
}
1159911626
else
1160011627
{

gcc/rust/parse/rust-parse.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,15 @@ namespace Rust {
2727
* probably take up the same amount of space. */
2828
struct ExprOrStmt
2929
{
30-
std::unique_ptr<AST::ExprWithoutBlock> expr;
30+
std::unique_ptr<AST::Expr> expr;
3131
std::unique_ptr<AST::Stmt> stmt;
3232

3333
/* I was going to resist the urge to make this a real class and make it POD,
3434
* but construction in steps is too difficult. So it'll just also have a
3535
* constructor. */
3636

3737
// expression constructor
38-
ExprOrStmt (std::unique_ptr<AST::ExprWithoutBlock> expr)
39-
: expr (std::move (expr))
40-
{}
38+
ExprOrStmt (std::unique_ptr<AST::Expr> expr) : expr (std::move (expr)) {}
4139

4240
// statement constructor
4341
ExprOrStmt (std::unique_ptr<AST::Stmt> stmt) : stmt (std::move (stmt)) {}
@@ -63,9 +61,7 @@ struct ExprOrStmt
6361

6462
private:
6563
// private constructor only used for creating error state expr or stmt objects
66-
ExprOrStmt (AST::ExprWithoutBlock *expr, AST::Stmt *stmt)
67-
: expr (expr), stmt (stmt)
68-
{}
64+
ExprOrStmt (AST::Expr *expr, AST::Stmt *stmt) : expr (expr), stmt (stmt) {}
6965

7066
// make this work: have a disambiguation specifically for known statements
7167
// (i.e. ';' and 'let'). then, have a special "parse expr or stmt" function
@@ -487,6 +483,8 @@ template <typename ManagedTokenSource> class Parser
487483
ParseRestrictions restrictions = ParseRestrictions ());
488484

489485
// Expression-related (non-Pratt parsed)
486+
std::unique_ptr<AST::ExprWithBlock>
487+
parse_expr_with_block (std::vector<AST::Attribute> outer_attrs);
490488
std::unique_ptr<AST::ExprWithoutBlock>
491489
parse_expr_without_block (std::vector<AST::Attribute> outer_attrs
492490
= std::vector<AST::Attribute> ());
@@ -592,6 +590,8 @@ template <typename ManagedTokenSource> class Parser
592590
parse_expr_stmt_without_block (std::vector<AST::Attribute> outer_attrs);
593591
ExprOrStmt parse_stmt_or_expr_without_block ();
594592
ExprOrStmt
593+
parse_stmt_or_expr_with_block (std::vector<AST::Attribute> outer_attrs);
594+
ExprOrStmt
595595
parse_macro_invocation_maybe_semi (std::vector<AST::Attribute> outer_attrs);
596596
ExprOrStmt
597597
parse_path_based_stmt_or_expr (std::vector<AST::Attribute> outer_attrs);

gcc/rust/typecheck/rust-hir-type-check.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
143143
delete block_tyty;
144144
block_tyty = resolved;
145145
}
146-
else if (!resolved->is_unit ())
146+
else if (s->is_unit_check_needed () && !resolved->is_unit ())
147147
{
148-
rust_error_at (s->get_locus_slow (), "expected () got %s",
149-
resolved->as_string ().c_str ());
148+
auto unit = new TyTy::TupleType (s->get_mappings ().get_hirid ());
149+
resolved = unit->unify (resolved);
150150
}
151151

152152
return true;

gcc/testsuite/rust.test/compile/unused.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ fn f() {
1414

1515
fn main() {
1616
f();
17-
}
17+
}

gcc/testsuite/rust.test/xfail_compile/implicit_returns_err1.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 }
2-
31
fn test(x: i32) -> i32 {
4-
if x > 1 {
2+
if x > 1 { // { dg-error "expected .... got .<integer>." }
53
1
64
} else {
75
2

gcc/testsuite/rust.test/xfail_compile/implicit_returns_err3.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// { dg-error "expected .* got .*" "" { target { *-*-* } } 0 }
2-
fn test(x: i32) -> i32 {
1+
fn test(x: i32) -> i32 { // { dg-error "expected .i32. got ...." }
32
if x > 1 {
43
1
54
}

0 commit comments

Comments
 (0)