From 50f671c667c35d34b86c1a20ccc775737fceb343 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 30 Mar 2012 04:59:02 +0000 Subject: [PATCH] compiler: Fix order of evaluation of struct composite literals. From-SVN: r185990 --- gcc/go/gofrontend/expressions.cc | 49 +++++++++++++++++++++++++++----- gcc/go/gofrontend/expressions.h | 5 ++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 06e85eb8de2..baff0c9a5d9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10967,9 +10967,15 @@ class Struct_construction_expression : public Expression 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* traverse_order) + { this->traverse_order_ = traverse_order; } + // Return whether this is a constant initializer. bool is_constant_struct() const; @@ -10991,8 +10997,12 @@ class Struct_construction_expression : public Expression 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 @@ class Struct_construction_expression : public Expression // 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* traverse_order_; }; // Traversal. @@ -11017,9 +11030,26 @@ class Struct_construction_expression : public Expression 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::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 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) size_t field_count = st->field_count(); std::vector vals(field_count); + std::vector* traverse_order = new(std::vector); Expression_list::const_iterator p = this->vals_->begin(); while (p != this->vals_->end()) { @@ -12350,6 +12381,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) 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 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) 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 --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 090e893f25e..d58e6c5fcb0 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -842,6 +842,11 @@ class Expression_list 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()