OSDN Git Service

Implement new order of assignment rules.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 25 Oct 2011 05:37:48 +0000 (05:37 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 25 Oct 2011 05:37:48 +0000 (05:37 +0000)
In "i, x[i] = 1, 2" the assigment to x[i] must use the value
of i from before the assignment statement.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180421 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/statements.cc

index e61dd3b..180279e 100644 (file)
@@ -3993,6 +3993,10 @@ class Unary_expression : public Expression
   }
 
   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 @@ class Array_index_expression : public Expression
   }
 
   bool
+  do_must_eval_subexpressions_in_order(int* skip) const
+  {
+    *skip = 1;
+    return true;
+  }
+
+  bool
   do_is_addressable() const;
 
   void
@@ -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*);
 
index 8cdf94d..a1f03c4 100644 (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
index c079fdf..abc629e 100644 (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());