Commit cbe98a41 by Ian Lance Taylor

Implement new order of assignment rules.

In "i, x[i] = 1, 2" the assigment to x[i] must use the value
of i from before the assignment statement.

From-SVN: r180421
parent cbffbd59
...@@ -3993,6 +3993,10 @@ class Unary_expression : public Expression ...@@ -3993,6 +3993,10 @@ class Unary_expression : public Expression
} }
bool bool
do_must_eval_subexpressions_in_order(int*) const
{ return this->op_ == OPERATOR_MULT; }
bool
do_is_addressable() const do_is_addressable() const
{ return this->op_ == OPERATOR_MULT; } { return this->op_ == OPERATOR_MULT; }
...@@ -10037,6 +10041,13 @@ class Array_index_expression : public Expression ...@@ -10037,6 +10041,13 @@ class Array_index_expression : public Expression
} }
bool bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
bool
do_is_addressable() const; do_is_addressable() const;
void void
...@@ -10461,6 +10472,13 @@ class String_index_expression : public Expression ...@@ -10461,6 +10472,13 @@ class String_index_expression : public Expression
this->location()); this->location());
} }
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
tree tree
do_get_tree(Translate_context*); do_get_tree(Translate_context*);
......
...@@ -582,6 +582,18 @@ class Expression ...@@ -582,6 +582,18 @@ class Expression
must_eval_in_order() const must_eval_in_order() const
{ return this->do_must_eval_in_order(); } { return this->do_must_eval_in_order(); }
// Return whether subexpressions of this expression must be
// evaluated in order. This is true of index expressions and
// pointer indirections. This sets *SKIP to the number of
// subexpressions to skip during traversing, as index expressions
// only requiring moving the index, not the array.
bool
must_eval_subexpressions_in_order(int* skip) const
{
*skip = 0;
return this->do_must_eval_subexpressions_in_order(skip);
}
// Return the tree for this expression. // Return the tree for this expression.
tree tree
get_tree(Translate_context*); get_tree(Translate_context*);
...@@ -717,6 +729,13 @@ class Expression ...@@ -717,6 +729,13 @@ class Expression
do_must_eval_in_order() const do_must_eval_in_order() const
{ return false; } { return false; }
// Child class implements whether this expressions requires that
// subexpressions be evaluated in order. The child implementation
// may set *SKIP if it should be non-zero.
virtual bool
do_must_eval_subexpressions_in_order(int* /* skip */) const
{ return false; }
// Child class implements conversion to tree. // Child class implements conversion to tree.
virtual tree virtual tree
do_get_tree(Translate_context*) = 0; do_get_tree(Translate_context*) = 0;
...@@ -1526,6 +1545,13 @@ class Index_expression : public Parser_expression ...@@ -1526,6 +1545,13 @@ class Index_expression : public Parser_expression
this->location()); this->location());
} }
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
void void
do_dump_expression(Ast_dump_context*) const; do_dump_expression(Ast_dump_context*) const;
...@@ -1623,6 +1649,13 @@ class Map_index_expression : public Expression ...@@ -1623,6 +1649,13 @@ class Map_index_expression : public Expression
this->location()); this->location());
} }
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
// A map index expression is an lvalue but it is not addressable. // A map index expression is an lvalue but it is not addressable.
tree tree
......
...@@ -652,6 +652,47 @@ Statement::make_assignment(Expression* lhs, Expression* rhs, ...@@ -652,6 +652,47 @@ Statement::make_assignment(Expression* lhs, Expression* rhs,
return new Assignment_statement(lhs, rhs, location); return new Assignment_statement(lhs, rhs, location);
} }
// The Move_subexpressions class is used to move all top-level
// subexpressions of an expression. This is used for things like
// index expressions in which we must evaluate the index value before
// it can be changed by a multiple assignment.
class Move_subexpressions : public Traverse
{
public:
Move_subexpressions(int skip, Block* block)
: Traverse(traverse_expressions),
skip_(skip), block_(block)
{ }
protected:
int
expression(Expression**);
private:
// The number of subexpressions to skip moving. This is used to
// avoid moving the array itself, as we only need to move the index.
int skip_;
// The block where new temporary variables should be added.
Block* block_;
};
int
Move_subexpressions::expression(Expression** pexpr)
{
if (this->skip_ > 0)
--this->skip_;
else if ((*pexpr)->temporary_reference_expression() == NULL)
{
source_location loc = (*pexpr)->location();
Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
this->block_->add_statement(temp);
*pexpr = Expression::make_temporary_reference(temp, loc);
}
// We only need to move top-level subexpressions.
return TRAVERSE_SKIP_COMPONENTS;
}
// The Move_ordered_evals class is used to find any subexpressions of // The Move_ordered_evals class is used to find any subexpressions of
// an expression that have an evaluation order dependency. It creates // an expression that have an evaluation order dependency. It creates
// temporary variables to hold them. // temporary variables to hold them.
...@@ -679,6 +720,15 @@ Move_ordered_evals::expression(Expression** pexpr) ...@@ -679,6 +720,15 @@ Move_ordered_evals::expression(Expression** pexpr)
// We have to look at subexpressions first. // We have to look at subexpressions first.
if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT) if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
return TRAVERSE_EXIT; return TRAVERSE_EXIT;
int i;
if ((*pexpr)->must_eval_subexpressions_in_order(&i))
{
Move_subexpressions ms(i, this->block_);
if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
if ((*pexpr)->must_eval_in_order()) if ((*pexpr)->must_eval_in_order())
{ {
source_location loc = (*pexpr)->location(); source_location loc = (*pexpr)->location();
...@@ -901,10 +951,10 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -901,10 +951,10 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
// First move out any subexpressions on the left hand side. The // First move out any subexpressions on the left hand side. The
// right hand side will be evaluated in the required order anyhow. // right hand side will be evaluated in the required order anyhow.
Move_ordered_evals moe(b); Move_ordered_evals moe(b);
for (Expression_list::const_iterator plhs = this->lhs_->begin(); for (Expression_list::iterator plhs = this->lhs_->begin();
plhs != this->lhs_->end(); plhs != this->lhs_->end();
++plhs) ++plhs)
(*plhs)->traverse_subexpressions(&moe); Expression::traverse(&*plhs, &moe);
std::vector<Temporary_statement*> temps; std::vector<Temporary_statement*> temps;
temps.reserve(this->lhs_->size()); temps.reserve(this->lhs_->size());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment