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:
parent
cbffbd59d6
commit
cbe98a41a5
3 changed files with 103 additions and 2 deletions
|
@ -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*);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Add table
Reference in a new issue