Skip to content

Fix issues about block expression evaluation #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions gcc/rust/ast/rust-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -2842,7 +2842,7 @@ class BlockExpr : public ExprWithBlock
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)),
Expand All @@ -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)
Expand All @@ -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;

Expand Down Expand Up @@ -2929,7 +2929,7 @@ class BlockExpr : public ExprWithBlock
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;
Expand Down
9 changes: 7 additions & 2 deletions gcc/rust/ast/rust-stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,17 @@ class ExprStmtWithoutBlock : public ExprStmt
class ExprStmtWithBlock : public ExprStmt
{
std::unique_ptr<ExprWithBlock> expr;
bool semicolon_followed;

public:
std::string as_string () const override;

std::vector<LetStmt *> locals;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right grammar? https://doc.rust-lang.org/stable/reference/statements.html

@SimplyTheOther what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it does look like what @yizhepku mentioned in #317 which seems right

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"An expression that consists of only a block expression or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon. [...] When the trailing semicolon is omitted, the result must be type ()." quoted from https://doc.rust-lang.org/stable/reference/statements.html. So I think it is right.

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
Expand Down Expand Up @@ -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 */
Expand Down
5 changes: 5 additions & 0 deletions gcc/rust/backend/rust-compile-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,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) {}

Expand Down
5 changes: 5 additions & 0 deletions gcc/rust/backend/rust-compile-tyty.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
9 changes: 4 additions & 5 deletions gcc/rust/backend/rust-compile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/hir/rust-ast-lower-stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ class ASTLoweringStmt : public ASTLoweringBase
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);
Expand Down
2 changes: 1 addition & 1 deletion gcc/rust/hir/rust-ast-lower.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions gcc/rust/hir/tree/rust-hir-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2489,7 +2489,7 @@ class BlockExpr : public ExprWithBlock
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;
Expand All @@ -2502,11 +2502,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<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)),
Expand All @@ -2522,7 +2522,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)
Expand All @@ -2534,7 +2534,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;
Expand Down Expand Up @@ -2580,7 +2580,7 @@ class BlockExpr : public ExprWithBlock
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; }

Expand Down
9 changes: 7 additions & 2 deletions gcc/rust/hir/tree/rust-hir-stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,16 @@ class ExprStmtWithoutBlock : public ExprStmt
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
Expand All @@ -224,6 +227,8 @@ class ExprStmtWithBlock : public ExprStmt

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 */
Expand Down
2 changes: 2 additions & 0 deletions gcc/rust/hir/tree/rust-hir.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,8 @@ class Stmt
* 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:
Expand Down
61 changes: 44 additions & 17 deletions gcc/rust/parse/rust-parse-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
{
Expand Down
Loading