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
This commit is contained in:
Ian Lance Taylor 2011-10-25 05:37:48 +00:00
parent cbffbd59d6
commit cbe98a41a5
3 changed files with 103 additions and 2 deletions

View file

@ -3992,6 +3992,10 @@ class Unary_expression : public Expression
this->location());
}
bool
do_must_eval_subexpressions_in_order(int*) const
{ return this->op_ == OPERATOR_MULT; }
bool
do_is_addressable() const
{ return this->op_ == OPERATOR_MULT; }
@ -10036,6 +10040,13 @@ class Array_index_expression : public Expression
this->location());
}
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
bool
do_is_addressable() const;
@ -10461,6 +10472,13 @@ class String_index_expression : public Expression
this->location());
}
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
tree
do_get_tree(Translate_context*);

View file

@ -582,6 +582,18 @@ class Expression
must_eval_in_order() const
{ 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.
tree
get_tree(Translate_context*);
@ -717,6 +729,13 @@ class Expression
do_must_eval_in_order() const
{ 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.
virtual tree
do_get_tree(Translate_context*) = 0;
@ -1526,6 +1545,13 @@ class Index_expression : public Parser_expression
this->location());
}
bool
do_must_eval_subexpressions_in_order(int* skip) const
{
*skip = 1;
return true;
}
void
do_dump_expression(Ast_dump_context*) const;
@ -1623,6 +1649,13 @@ class Map_index_expression : public Expression
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.
tree

View file

@ -652,6 +652,47 @@ Statement::make_assignment(Expression* lhs, Expression* rhs,
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
// an expression that have an evaluation order dependency. It creates
// temporary variables to hold them.
@ -679,6 +720,15 @@ Move_ordered_evals::expression(Expression** pexpr)
// We have to look at subexpressions first.
if ((*pexpr)->traverse_subexpressions(this) == 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())
{
source_location loc = (*pexpr)->location();
@ -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
// right hand side will be evaluated in the required order anyhow.
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)
(*plhs)->traverse_subexpressions(&moe);
Expression::traverse(&*plhs, &moe);
std::vector<Temporary_statement*> temps;
temps.reserve(this->lhs_->size());