@@ -3993,6 +3993,10 @@
}
bool
+ do_must_eval_subexpressions_in_order(int*) const
+ { return this->op_ == OPERATOR_MULT; }
+
+ bool
do_is_addressable() const
{ return this->op_ == OPERATOR_MULT; }
@@ -10037,6 +10041,13 @@
}
bool
+ do_must_eval_subexpressions_in_order(int* skip) const
+ {
+ *skip = 1;
+ return true;
+ }
+
+ bool
do_is_addressable() const;
void
@@ -10461,6 +10472,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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());