compiler: fix for expr sharing introduced by Order_eval::statement.
When processing an expression statement with a top-level call
that returns multiple results, Order_eval::statement can wind up
creating a tree that has multiple references to the same call,
which results in a confusing AST dump. Change the implementation
to avoid introducing this unwanted sharing.
Change-Id: I3781934a9358a3d3361c7baf24d305577c55cd29
Reviewed-on: https://go-review.googlesource.com/39210
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/go/gogo.cc b/go/gogo.cc
index 82d15c3..12135d7 100644
--- a/go/gogo.cc
+++ b/go/gogo.cc
@@ -3620,14 +3620,14 @@
// Implement the order of evaluation rules for a statement.
int
-Order_eval::statement(Block* block, size_t* pindex, Statement* s)
+Order_eval::statement(Block* block, size_t* pindex, Statement* stmt)
{
// FIXME: This approach doesn't work for switch statements, because
// we add the new statements before the whole switch when we need to
// instead add them just before the switch expression. The right
// fix is probably to lower switch statements with nonconstant cases
// to a series of conditionals.
- if (s->switch_statement() != NULL)
+ if (stmt->switch_statement() != NULL)
return TRAVERSE_CONTINUE;
Find_eval_ordering find_eval_ordering;
@@ -3635,11 +3635,11 @@
// If S is a variable declaration, then ordinary traversal won't do
// anything. We want to explicitly traverse the initialization
// expression if there is one.
- Variable_declaration_statement* vds = s->variable_declaration_statement();
+ Variable_declaration_statement* vds = stmt->variable_declaration_statement();
Expression* init = NULL;
Expression* orig_init = NULL;
if (vds == NULL)
- s->traverse_contents(&find_eval_ordering);
+ stmt->traverse_contents(&find_eval_ordering);
else
{
init = vds->var()->var_value()->init();
@@ -3672,7 +3672,7 @@
// usually leave it in place.
if (c == 1)
{
- switch (s->classification())
+ switch (stmt->classification())
{
case Statement::STATEMENT_ASSIGNMENT:
// For an assignment statement, we need to evaluate an
@@ -3689,7 +3689,7 @@
// move. We need to move any subexpressions in case they
// are themselves call statements that require passing a
// closure.
- Expression* expr = s->expression_statement()->expr();
+ Expression* expr = stmt->expression_statement()->expr();
if (expr->call_expression() != NULL
&& expr->call_expression()->result_count() == 0)
break;
@@ -3702,7 +3702,8 @@
}
}
- bool is_thunk = s->thunk_statement() != NULL;
+ bool is_thunk = stmt->thunk_statement() != NULL;
+ Expression_statement* es = stmt->expression_statement();
for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
p != find_eval_ordering.end();
++p)
@@ -3733,9 +3734,14 @@
//
// Since a given call expression can be shared by multiple
// Call_result_expressions, avoid hoisting the call the
- // second time we see it here.
+ // second time we see it here. In addition, don't try to
+ // hoist the top-level multi-return call in the statement,
+ // since doing this would result a tree with more than one copy
+ // of the call.
if (this->remember_expression(*pexpr))
s = NULL;
+ else if (es != NULL && *pexpr == es->expr())
+ s = NULL;
else
s = Statement::make_statement(*pexpr, true);
}