Commit e9d33505 by Ian Lance Taylor

compiler: fix slice/array evaluation order bug

    
    There was a phase ordering issue in the handling of "keyed" array
    literal expressions: the lowering phase was canonicalizing the
    indices/vals before the phase that fixed evaluation order, meaning that
    the evaluation order was incorrect. The fix is to capture the orginal
    ordering and use that ordering when doing traversals (there is already
    something similar being done for struct literal expressions).
    
    Fixes golang/go#17640
    
    Reviewed-on: https://go-review.googlesource.com/32296

From-SVN: r241688
parent 48e21b40
4ca21c94f00c620bfde2f924e214c78fe2e1ff69 c353ffbe18d1538cac7f2a3fcefb846dbf1a6591
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -12202,12 +12202,10 @@ Expression::make_allocation(Type* type, Location location) ...@@ -12202,12 +12202,10 @@ Expression::make_allocation(Type* type, Location location)
return new Allocation_expression(type, location); return new Allocation_expression(type, location);
} }
// Class Struct_construction_expression. // Class Ordered_value_list.
// Traversal.
int int
Struct_construction_expression::do_traverse(Traverse* traverse) Ordered_value_list::traverse_vals(Traverse* traverse)
{ {
if (this->vals_ != NULL) if (this->vals_ != NULL)
{ {
...@@ -12218,8 +12216,8 @@ Struct_construction_expression::do_traverse(Traverse* traverse) ...@@ -12218,8 +12216,8 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
} }
else else
{ {
for (std::vector<int>::const_iterator p = for (std::vector<unsigned long>::const_iterator p =
this->traverse_order_->begin(); this->traverse_order_->begin();
p != this->traverse_order_->end(); p != this->traverse_order_->end();
++p) ++p)
{ {
...@@ -12229,6 +12227,18 @@ Struct_construction_expression::do_traverse(Traverse* traverse) ...@@ -12229,6 +12227,18 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
} }
} }
} }
return TRAVERSE_CONTINUE;
}
// Class Struct_construction_expression.
// Traversal.
int
Struct_construction_expression::do_traverse(Traverse* traverse)
{
if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT; return TRAVERSE_EXIT;
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
...@@ -12239,10 +12249,10 @@ Struct_construction_expression::do_traverse(Traverse* traverse) ...@@ -12239,10 +12249,10 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
bool bool
Struct_construction_expression::is_constant_struct() const Struct_construction_expression::is_constant_struct() const
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return true; return true;
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL if (*pv != NULL
...@@ -12270,10 +12280,10 @@ Struct_construction_expression::is_constant_struct() const ...@@ -12270,10 +12280,10 @@ Struct_construction_expression::is_constant_struct() const
bool bool
Struct_construction_expression::do_is_immutable() const Struct_construction_expression::do_is_immutable() const
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return true; return true;
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL && !(*pv)->is_immutable()) if (*pv != NULL && !(*pv)->is_immutable())
...@@ -12287,15 +12297,15 @@ Struct_construction_expression::do_is_immutable() const ...@@ -12287,15 +12297,15 @@ Struct_construction_expression::do_is_immutable() const
void void
Struct_construction_expression::do_determine_type(const Type_context*) Struct_construction_expression::do_determine_type(const Type_context*)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return; return;
const Struct_field_list* fields = this->type_->struct_type()->fields(); const Struct_field_list* fields = this->type_->struct_type()->fields();
Expression_list::const_iterator pv = this->vals_->begin(); Expression_list::const_iterator pv = this->vals()->begin();
for (Struct_field_list::const_iterator pf = fields->begin(); for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end(); pf != fields->end();
++pf, ++pv) ++pf, ++pv)
{ {
if (pv == this->vals_->end()) if (pv == this->vals()->end())
return; return;
if (*pv != NULL) if (*pv != NULL)
{ {
...@@ -12305,7 +12315,7 @@ Struct_construction_expression::do_determine_type(const Type_context*) ...@@ -12305,7 +12315,7 @@ Struct_construction_expression::do_determine_type(const Type_context*)
} }
// Extra values are an error we will report elsewhere; we still want // Extra values are an error we will report elsewhere; we still want
// to determine the type to avoid knockon errors. // to determine the type to avoid knockon errors.
for (; pv != this->vals_->end(); ++pv) for (; pv != this->vals()->end(); ++pv)
(*pv)->determine_type_no_context(); (*pv)->determine_type_no_context();
} }
...@@ -12314,24 +12324,24 @@ Struct_construction_expression::do_determine_type(const Type_context*) ...@@ -12314,24 +12324,24 @@ Struct_construction_expression::do_determine_type(const Type_context*)
void void
Struct_construction_expression::do_check_types(Gogo*) Struct_construction_expression::do_check_types(Gogo*)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return; return;
Struct_type* st = this->type_->struct_type(); Struct_type* st = this->type_->struct_type();
if (this->vals_->size() > st->field_count()) if (this->vals()->size() > st->field_count())
{ {
this->report_error(_("too many expressions for struct")); this->report_error(_("too many expressions for struct"));
return; return;
} }
const Struct_field_list* fields = st->fields(); const Struct_field_list* fields = st->fields();
Expression_list::const_iterator pv = this->vals_->begin(); Expression_list::const_iterator pv = this->vals()->begin();
int i = 0; int i = 0;
for (Struct_field_list::const_iterator pf = fields->begin(); for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end(); pf != fields->end();
++pf, ++pv, ++i) ++pf, ++pv, ++i)
{ {
if (pv == this->vals_->end()) if (pv == this->vals()->end())
{ {
this->report_error(_("too few expressions for struct")); this->report_error(_("too few expressions for struct"));
break; break;
...@@ -12355,7 +12365,7 @@ Struct_construction_expression::do_check_types(Gogo*) ...@@ -12355,7 +12365,7 @@ Struct_construction_expression::do_check_types(Gogo*)
this->set_is_error(); this->set_is_error();
} }
} }
go_assert(pv == this->vals_->end()); go_assert(pv == this->vals()->end());
} }
// Flatten a struct construction expression. Store the values into // Flatten a struct construction expression. Store the values into
...@@ -12365,7 +12375,7 @@ Expression* ...@@ -12365,7 +12375,7 @@ Expression*
Struct_construction_expression::do_flatten(Gogo*, Named_object*, Struct_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter) Statement_inserter* inserter)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return this; return this;
// If this is a constant struct, we don't need temporaries. // If this is a constant struct, we don't need temporaries.
...@@ -12373,8 +12383,8 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*, ...@@ -12373,8 +12383,8 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*,
return this; return this;
Location loc = this->location(); Location loc = this->location();
for (Expression_list::iterator pv = this->vals_->begin(); for (Expression_list::iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL) if (*pv != NULL)
...@@ -12404,18 +12414,18 @@ Struct_construction_expression::do_get_backend(Translate_context* context) ...@@ -12404,18 +12414,18 @@ Struct_construction_expression::do_get_backend(Translate_context* context)
Gogo* gogo = context->gogo(); Gogo* gogo = context->gogo();
Btype* btype = this->type_->get_backend(gogo); Btype* btype = this->type_->get_backend(gogo);
if (this->vals_ == NULL) if (this->vals() == NULL)
return gogo->backend()->zero_expression(btype); return gogo->backend()->zero_expression(btype);
const Struct_field_list* fields = this->type_->struct_type()->fields(); const Struct_field_list* fields = this->type_->struct_type()->fields();
Expression_list::const_iterator pv = this->vals_->begin(); Expression_list::const_iterator pv = this->vals()->begin();
std::vector<Bexpression*> init; std::vector<Bexpression*> init;
for (Struct_field_list::const_iterator pf = fields->begin(); for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end(); pf != fields->end();
++pf) ++pf)
{ {
Btype* fbtype = pf->type()->get_backend(gogo); Btype* fbtype = pf->type()->get_backend(gogo);
if (pv == this->vals_->end()) if (pv == this->vals()->end())
init.push_back(gogo->backend()->zero_expression(fbtype)); init.push_back(gogo->backend()->zero_expression(fbtype));
else if (*pv == NULL) else if (*pv == NULL)
{ {
...@@ -12441,8 +12451,8 @@ Struct_construction_expression::do_export(Export* exp) const ...@@ -12441,8 +12451,8 @@ Struct_construction_expression::do_export(Export* exp) const
{ {
exp->write_c_string("convert("); exp->write_c_string("convert(");
exp->write_type(this->type_); exp->write_type(this->type_);
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
exp->write_c_string(", "); exp->write_c_string(", ");
...@@ -12460,7 +12470,7 @@ Struct_construction_expression::do_dump_expression( ...@@ -12460,7 +12470,7 @@ Struct_construction_expression::do_dump_expression(
{ {
ast_dump_context->dump_type(this->type_); ast_dump_context->dump_type(this->type_);
ast_dump_context->ostream() << "{"; ast_dump_context->ostream() << "{";
ast_dump_context->dump_expression_list(this->vals_); ast_dump_context->dump_expression_list(this->vals());
ast_dump_context->ostream() << "}"; ast_dump_context->ostream() << "}";
} }
...@@ -12481,8 +12491,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals, ...@@ -12481,8 +12491,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
int int
Array_construction_expression::do_traverse(Traverse* traverse) Array_construction_expression::do_traverse(Traverse* traverse)
{ {
if (this->vals_ != NULL if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
&& this->vals_->traverse(traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT; return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT; return TRAVERSE_EXIT;
...@@ -12494,15 +12503,15 @@ Array_construction_expression::do_traverse(Traverse* traverse) ...@@ -12494,15 +12503,15 @@ Array_construction_expression::do_traverse(Traverse* traverse)
bool bool
Array_construction_expression::is_constant_array() const Array_construction_expression::is_constant_array() const
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return true; return true;
// There are no constant constructors for interfaces. // There are no constant constructors for interfaces.
if (this->type_->array_type()->element_type()->interface_type() != NULL) if (this->type_->array_type()->element_type()->interface_type() != NULL)
return false; return false;
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL if (*pv != NULL
...@@ -12519,10 +12528,10 @@ Array_construction_expression::is_constant_array() const ...@@ -12519,10 +12528,10 @@ Array_construction_expression::is_constant_array() const
bool bool
Array_construction_expression::do_is_immutable() const Array_construction_expression::do_is_immutable() const
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return true; return true;
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL && !(*pv)->is_immutable()) if (*pv != NULL && !(*pv)->is_immutable())
...@@ -12536,11 +12545,11 @@ Array_construction_expression::do_is_immutable() const ...@@ -12536,11 +12545,11 @@ Array_construction_expression::do_is_immutable() const
void void
Array_construction_expression::do_determine_type(const Type_context*) Array_construction_expression::do_determine_type(const Type_context*)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return; return;
Type_context subcontext(this->type_->array_type()->element_type(), false); Type_context subcontext(this->type_->array_type()->element_type(), false);
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL) if (*pv != NULL)
...@@ -12553,14 +12562,14 @@ Array_construction_expression::do_determine_type(const Type_context*) ...@@ -12553,14 +12562,14 @@ Array_construction_expression::do_determine_type(const Type_context*)
void void
Array_construction_expression::do_check_types(Gogo*) Array_construction_expression::do_check_types(Gogo*)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return; return;
Array_type* at = this->type_->array_type(); Array_type* at = this->type_->array_type();
int i = 0; int i = 0;
Type* element_type = at->element_type(); Type* element_type = at->element_type();
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv, ++i) ++pv, ++i)
{ {
if (*pv != NULL if (*pv != NULL
...@@ -12581,7 +12590,7 @@ Expression* ...@@ -12581,7 +12590,7 @@ Expression*
Array_construction_expression::do_flatten(Gogo*, Named_object*, Array_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter) Statement_inserter* inserter)
{ {
if (this->vals_ == NULL) if (this->vals() == NULL)
return this; return this;
// If this is a constant array, we don't need temporaries. // If this is a constant array, we don't need temporaries.
...@@ -12589,8 +12598,8 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*, ...@@ -12589,8 +12598,8 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*,
return this; return this;
Location loc = this->location(); Location loc = this->location();
for (Expression_list::iterator pv = this->vals_->begin(); for (Expression_list::iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
if (*pv != NULL) if (*pv != NULL)
...@@ -12623,14 +12632,14 @@ Array_construction_expression::get_constructor(Translate_context* context, ...@@ -12623,14 +12632,14 @@ Array_construction_expression::get_constructor(Translate_context* context,
std::vector<unsigned long> indexes; std::vector<unsigned long> indexes;
std::vector<Bexpression*> vals; std::vector<Bexpression*> vals;
Gogo* gogo = context->gogo(); Gogo* gogo = context->gogo();
if (this->vals_ != NULL) if (this->vals() != NULL)
{ {
size_t i = 0; size_t i = 0;
std::vector<unsigned long>::const_iterator pi; std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL) if (this->indexes_ != NULL)
pi = this->indexes_->begin(); pi = this->indexes_->begin();
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv, ++i) ++pv, ++i)
{ {
if (this->indexes_ != NULL) if (this->indexes_ != NULL)
...@@ -12670,13 +12679,13 @@ Array_construction_expression::do_export(Export* exp) const ...@@ -12670,13 +12679,13 @@ Array_construction_expression::do_export(Export* exp) const
{ {
exp->write_c_string("convert("); exp->write_c_string("convert(");
exp->write_type(this->type_); exp->write_type(this->type_);
if (this->vals_ != NULL) if (this->vals() != NULL)
{ {
std::vector<unsigned long>::const_iterator pi; std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL) if (this->indexes_ != NULL)
pi = this->indexes_->begin(); pi = this->indexes_->begin();
for (Expression_list::const_iterator pv = this->vals_->begin(); for (Expression_list::const_iterator pv = this->vals()->begin();
pv != this->vals_->end(); pv != this->vals()->end();
++pv) ++pv)
{ {
exp->write_c_string(", "); exp->write_c_string(", ");
...@@ -12717,10 +12726,10 @@ Array_construction_expression::do_dump_expression( ...@@ -12717,10 +12726,10 @@ Array_construction_expression::do_dump_expression(
this->dump_slice_storage_expression(ast_dump_context); this->dump_slice_storage_expression(ast_dump_context);
ast_dump_context->ostream() << "{" ; ast_dump_context->ostream() << "{" ;
if (this->indexes_ == NULL) if (this->indexes_ == NULL)
ast_dump_context->dump_expression_list(this->vals_); ast_dump_context->dump_expression_list(this->vals());
else else
{ {
Expression_list::const_iterator pv = this->vals_->begin(); Expression_list::const_iterator pv = this->vals()->begin();
for (std::vector<unsigned long>::const_iterator pi = for (std::vector<unsigned long>::const_iterator pi =
this->indexes_->begin(); this->indexes_->begin();
pi != this->indexes_->end(); pi != this->indexes_->end();
...@@ -13349,7 +13358,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -13349,7 +13358,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
size_t field_count = st->field_count(); size_t field_count = st->field_count();
std::vector<Expression*> vals(field_count); std::vector<Expression*> vals(field_count);
std::vector<int>* traverse_order = new(std::vector<int>); std::vector<unsigned long>* traverse_order = new(std::vector<unsigned long>);
Expression_list::const_iterator p = this->vals_->begin(); Expression_list::const_iterator p = this->vals_->begin();
Expression* external_expr = NULL; Expression* external_expr = NULL;
const Named_object* external_no = NULL; const Named_object* external_no = NULL;
...@@ -13481,7 +13490,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -13481,7 +13490,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
type->named_type()->message_name().c_str()); type->named_type()->message_name().c_str());
vals[index] = val; vals[index] = val;
traverse_order->push_back(index); traverse_order->push_back(static_cast<unsigned long>(index));
} }
if (!this->all_are_names_) if (!this->all_are_names_)
...@@ -13512,15 +13521,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -13512,15 +13521,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
return ret; return ret;
} }
// Used to sort an index/value array. // Index/value/traversal-order triple.
class Index_value_compare struct IVT_triple {
{ unsigned long index;
public: unsigned long traversal_order;
bool Expression* expr;
operator()(const std::pair<unsigned long, Expression*>& a, IVT_triple(unsigned long i, unsigned long to, Expression *e)
const std::pair<unsigned long, Expression*>& b) : index(i), traversal_order(to), expr(e) { }
{ return a.first < b.first; } bool operator<(const IVT_triple& other) const
{ return this->index < other.index; }
}; };
// Lower an array composite literal. // Lower an array composite literal.
...@@ -13624,35 +13634,45 @@ Composite_literal_expression::lower_array(Type* type) ...@@ -13624,35 +13634,45 @@ Composite_literal_expression::lower_array(Type* type)
indexes = NULL; indexes = NULL;
} }
std::vector<unsigned long>* traverse_order = NULL;
if (indexes_out_of_order) if (indexes_out_of_order)
{ {
typedef std::vector<std::pair<unsigned long, Expression*> > V; typedef std::vector<IVT_triple> V;
V v; V v;
v.reserve(indexes->size()); v.reserve(indexes->size());
std::vector<unsigned long>::const_iterator pi = indexes->begin(); std::vector<unsigned long>::const_iterator pi = indexes->begin();
unsigned long torder = 0;
for (Expression_list::const_iterator pe = vals->begin(); for (Expression_list::const_iterator pe = vals->begin();
pe != vals->end(); pe != vals->end();
++pe, ++pi) ++pe, ++pi, ++torder)
v.push_back(std::make_pair(*pi, *pe)); v.push_back(IVT_triple(*pi, torder, *pe));
std::sort(v.begin(), v.end(), Index_value_compare()); std::sort(v.begin(), v.end());
delete indexes; delete indexes;
delete vals; delete vals;
indexes = new std::vector<unsigned long>(); indexes = new std::vector<unsigned long>();
indexes->reserve(v.size()); indexes->reserve(v.size());
vals = new Expression_list(); vals = new Expression_list();
vals->reserve(v.size()); vals->reserve(v.size());
traverse_order = new std::vector<unsigned long>();
traverse_order->reserve(v.size());
for (V::const_iterator p = v.begin(); p != v.end(); ++p) for (V::const_iterator p = v.begin(); p != v.end(); ++p)
{ {
indexes->push_back(p->first); indexes->push_back(p->index);
vals->push_back(p->second); vals->push_back(p->expr);
traverse_order->push_back(p->traversal_order);
} }
} }
return this->make_array(type, indexes, vals); Expression* ret = this->make_array(type, indexes, vals);
Array_construction_expression* ace = ret->array_literal();
if (ace != NULL && traverse_order != NULL)
ace->set_traverse_order(traverse_order);
return ret;
} }
// Actually build the array composite literal. This handles // Actually build the array composite literal. This handles
......
...@@ -3232,31 +3232,64 @@ class Composite_literal_expression : public Parser_expression ...@@ -3232,31 +3232,64 @@ class Composite_literal_expression : public Parser_expression
std::vector<bool> key_path_; std::vector<bool> key_path_;
}; };
// Construct a struct. // Helper/mixin class for struct and array construction expressions;
// encapsulates a list of values plus an optional traversal order
// recording the order in which the values should be visited.
class Struct_construction_expression : public Expression class Ordered_value_list
{ {
public: public:
Struct_construction_expression(Type* type, Expression_list* vals, Ordered_value_list(Expression_list* vals)
Location location) : vals_(vals), traverse_order_(NULL)
: Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
type_(type), vals_(vals), traverse_order_(NULL)
{ } { }
Expression_list*
vals() const
{ return this->vals_; }
int
traverse_vals(Traverse* traverse);
// Get the traversal order (may be NULL)
std::vector<unsigned long>*
traverse_order()
{ return traverse_order_; }
// Set the traversal order, used to ensure that we implement the // Set the traversal order, used to ensure that we implement the
// order of evaluation rules. Takes ownership of the argument. // order of evaluation rules. Takes ownership of the argument.
void void
set_traverse_order(std::vector<int>* traverse_order) set_traverse_order(std::vector<unsigned long>* traverse_order)
{ this->traverse_order_ = traverse_order; } { this->traverse_order_ = traverse_order; }
// Return whether this is a constant initializer. private:
// The list of values, in order of the fields in the struct or in
// order of indices in an array. A NULL value of vals_ means that
// all fields/slots should be zero-initialized; a single NULL entry
// in the list means that the corresponding field or array slot
// 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<unsigned long>* traverse_order_;
};
// Construct a struct.
class Struct_construction_expression : public Expression,
public Ordered_value_list
{
public:
Struct_construction_expression(Type* type, Expression_list* vals,
Location location)
: Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
Ordered_value_list(vals),
type_(type)
{ }
// Return whether this is a constant initializer.
bool bool
is_constant_struct() const; is_constant_struct() const;
Expression_list*
vals() const
{ return this->vals_; }
protected: protected:
int int
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
...@@ -3279,12 +3312,12 @@ class Struct_construction_expression : public Expression ...@@ -3279,12 +3312,12 @@ class Struct_construction_expression : public Expression
{ {
Struct_construction_expression* ret = Struct_construction_expression* ret =
new Struct_construction_expression(this->type_, new Struct_construction_expression(this->type_,
(this->vals_ == NULL (this->vals() == NULL
? NULL ? NULL
: this->vals_->copy()), : this->vals()->copy()),
this->location()); this->location());
if (this->traverse_order_ != NULL) if (this->traverse_order() != NULL)
ret->set_traverse_order(this->traverse_order_); ret->set_traverse_order(this->traverse_order());
return ret; return ret;
} }
...@@ -3303,19 +3336,14 @@ class Struct_construction_expression : public Expression ...@@ -3303,19 +3336,14 @@ class Struct_construction_expression : public Expression
private: private:
// The type of the struct to construct. // The type of the struct to construct.
Type* type_; Type* type_;
// 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_;
}; };
// Construct an array. This class is not used directly; instead we // Construct an array. This class is not used directly; instead we
// use the child classes, Fixed_array_construction_expression and // use the child classes, Fixed_array_construction_expression and
// Slice_construction_expression. // Slice_construction_expression.
class Array_construction_expression : public Expression class Array_construction_expression : public Expression,
public Ordered_value_list
{ {
protected: protected:
Array_construction_expression(Expression_classification classification, Array_construction_expression(Expression_classification classification,
...@@ -3323,7 +3351,8 @@ class Array_construction_expression : public Expression ...@@ -3323,7 +3351,8 @@ class Array_construction_expression : public Expression
const std::vector<unsigned long>* indexes, const std::vector<unsigned long>* indexes,
Expression_list* vals, Location location) Expression_list* vals, Location location)
: Expression(classification, location), : Expression(classification, location),
type_(type), indexes_(indexes), vals_(vals) Ordered_value_list(vals),
type_(type), indexes_(indexes)
{ go_assert(indexes == NULL || indexes->size() == vals->size()); } { go_assert(indexes == NULL || indexes->size() == vals->size()); }
public: public:
...@@ -3334,12 +3363,7 @@ class Array_construction_expression : public Expression ...@@ -3334,12 +3363,7 @@ class Array_construction_expression : public Expression
// Return the number of elements. // Return the number of elements.
size_t size_t
element_count() const element_count() const
{ return this->vals_ == NULL ? 0 : this->vals_->size(); } { return this->vals() == NULL ? 0 : this->vals()->size(); }
// The list of values.
Expression_list*
vals() const
{ return this->vals_; }
protected: protected:
virtual int virtual int
...@@ -3385,8 +3409,6 @@ protected: ...@@ -3385,8 +3409,6 @@ protected:
// The list of indexes into the array, one for each value. This may // The list of indexes into the array, one for each value. This may
// be NULL, in which case the indexes start at zero and increment. // be NULL, in which case the indexes start at zero and increment.
const std::vector<unsigned long>* indexes_; const std::vector<unsigned long>* indexes_;
// The list of values. This may be NULL if there are no values.
Expression_list* vals_;
}; };
// Construct a fixed array. // Construct a fixed array.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment