diff mbox

Go patch committed: Fix order of evaluation of struct literals

Message ID mcr7gy2d6qg.fsf@dhcp-172-18-216-180.mtv.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor March 30, 2012, 4:59 a.m. UTC
This patch to the Go compiler fixes the order of evaluation of struct
composite literals.  Previously the compiler assumed that all fields in
the struct were set in order.  However, the composite literal might be
written differently.  If the composite literal had function calls, Go
specifies that they are evaluated in the order in which they are
written.  This patch ensures that this is the case.  Bootstrapped and
ran Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r 07f8da93f9f4 go/expressions.cc
--- a/go/expressions.cc	Wed Mar 28 20:51:50 2012 -0700
+++ b/go/expressions.cc	Thu Mar 29 21:54:38 2012 -0700
@@ -10967,9 +10967,15 @@ 
   Struct_construction_expression(Type* type, Expression_list* vals,
 				 Location location)
     : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
-      type_(type), vals_(vals)
+      type_(type), vals_(vals), traverse_order_(NULL)
   { }
 
+  // Set the traversal order, used to ensure that we implement the
+  // order of evaluation rules.  Takes ownership of the argument.
+  void
+  set_traverse_order(std::vector<int>* traverse_order)
+  { this->traverse_order_ = traverse_order; }
+
   // Return whether this is a constant initializer.
   bool
   is_constant_struct() const;
@@ -10991,8 +10997,12 @@ 
   Expression*
   do_copy()
   {
-    return new Struct_construction_expression(this->type_, this->vals_->copy(),
-					      this->location());
+    Struct_construction_expression* ret =
+      new Struct_construction_expression(this->type_, this->vals_->copy(),
+					 this->location());
+    if (this->traverse_order_ != NULL)
+      ret->set_traverse_order(this->traverse_order_);
+    return ret;
   }
 
   tree
@@ -11010,6 +11020,9 @@ 
   // The list of values, in order of the fields in the struct.  A NULL
   // entry means that the field should be zero-initialized.
   Expression_list* vals_;
+  // If not NULL, the order in which to traverse vals_.  This is used
+  // so that we implement the order of evaluation rules correctly.
+  std::vector<int>* traverse_order_;
 };
 
 // Traversal.
@@ -11017,9 +11030,26 @@ 
 int
 Struct_construction_expression::do_traverse(Traverse* traverse)
 {
-  if (this->vals_ != NULL
-      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
-    return TRAVERSE_EXIT;
+  if (this->vals_ != NULL)
+    {
+      if (this->traverse_order_ == NULL)
+	{
+	  if (this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+	    return TRAVERSE_EXIT;
+	}
+      else
+	{
+	  for (std::vector<int>::const_iterator p =
+		 this->traverse_order_->begin();
+	       p != this->traverse_order_->end();
+	       ++p)
+	    {
+	      if (Expression::traverse(&this->vals_->at(*p), traverse)
+		  == TRAVERSE_EXIT)
+		return TRAVERSE_EXIT;
+	    }
+	}
+    }
   if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
     return TRAVERSE_EXIT;
   return TRAVERSE_CONTINUE;
@@ -12198,6 +12228,7 @@ 
 
   size_t field_count = st->field_count();
   std::vector<Expression*> vals(field_count);
+  std::vector<int>* traverse_order = new(std::vector<int>);
   Expression_list::const_iterator p = this->vals_->begin();
   while (p != this->vals_->end())
     {
@@ -12350,6 +12381,7 @@ 
 		 type->named_type()->message_name().c_str());
 
       vals[index] = val;
+      traverse_order->push_back(index);
     }
 
   Expression_list* list = new Expression_list;
@@ -12357,7 +12389,10 @@ 
   for (size_t i = 0; i < field_count; ++i)
     list->push_back(vals[i]);
 
-  return new Struct_construction_expression(type, list, location);
+  Struct_construction_expression* ret =
+    new Struct_construction_expression(type, list, location);
+  ret->set_traverse_order(traverse_order);
+  return ret;
 }
 
 // Lower an array composite literal.
diff -r 07f8da93f9f4 go/expressions.h
--- a/go/expressions.h	Wed Mar 28 20:51:50 2012 -0700
+++ b/go/expressions.h	Thu Mar 29 21:54:38 2012 -0700
@@ -842,6 +842,11 @@ 
   bool
   contains_error() const;
 
+  // Retrieve an element by index.
+  Expression*&
+  at(size_t i)
+  { return this->entries_.at(i); }
+
   // Return the first and last elements.
   Expression*&
   front()