This patch to the Go frontend updates the handling of iota to the current language spec; it was modified slightly in https://golang.org/cl/71750.
Also, the Go frontend has been mishandling iota appearing in a type that appears in a const expression, as in `c = len([iota]int{})`. Correct that by copying type expressions when we copy an expression. For simplicity only copy when it can change the size of a type, as that is the only case where iota in a type can affect the value of a constant (I think). This is still a bunch of changes, but almost all boilerplate. This fixes https://golang.org/22341. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 257378) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -d9f33a479f8012f7495d197e4b7417cba4d477fa +36594b69b94326014c331fe50a5a345ef4f8de16 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 257377) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -1928,10 +1928,16 @@ class Integer_expression : public Expres do_copy() { if (this->is_character_constant_) - return Expression::make_character(&this->val_, this->type_, + return Expression::make_character(&this->val_, + (this->type_ == NULL + ? NULL + : this->type_->copy_expressions()), this->location()); else - return Expression::make_integer_z(&this->val_, this->type_, + return Expression::make_integer_z(&this->val_, + (this->type_ == NULL + ? NULL + : this->type_->copy_expressions()), this->location()); } @@ -2323,7 +2329,10 @@ class Float_expression : public Expressi Expression* do_copy() - { return Expression::make_float(&this->val_, this->type_, + { return Expression::make_float(&this->val_, + (this->type_ == NULL + ? NULL + : this->type_->copy_expressions()), this->location()); } Bexpression* @@ -2514,7 +2523,10 @@ class Complex_expression : public Expres Expression* do_copy() { - return Expression::make_complex(&this->val_, this->type_, + return Expression::make_complex(&this->val_, + (this->type_ == NULL + ? NULL + : this->type_->copy_expressions()), this->location()); } @@ -3420,6 +3432,16 @@ Type_conversion_expression::do_check_typ this->set_is_error(); } +// Copy. + +Expression* +Type_conversion_expression::do_copy() +{ + return new Type_conversion_expression(this->type_->copy_expressions(), + this->expr_->copy(), + this->location()); +} + // Get the backend representation for a type conversion. Bexpression* @@ -3621,6 +3643,16 @@ Unsafe_type_conversion_expression::do_is return false; } +// Copy. + +Expression* +Unsafe_type_conversion_expression::do_copy() +{ + return new Unsafe_type_conversion_expression(this->type_->copy_expressions(), + this->expr_->copy(), + this->location()); +} + // Convert to backend representation. Bexpression* @@ -12401,7 +12433,8 @@ Expression* Allocation_expression::do_copy() { Allocation_expression* alloc = - new Allocation_expression(this->type_, this->location()); + new Allocation_expression(this->type_->copy_expressions(), + this->location()); if (this->allocate_on_stack_) alloc->set_allocate_on_stack(); return alloc; @@ -12641,6 +12674,22 @@ Struct_construction_expression::do_check go_assert(pv == this->vals()->end()); } +// Copy. + +Expression* +Struct_construction_expression::do_copy() +{ + Struct_construction_expression* ret = + new Struct_construction_expression(this->type_->copy_expressions(), + (this->vals() == NULL + ? NULL + : this->vals()->copy()), + this->location()); + if (this->traverse_order() != NULL) + ret->set_traverse_order(this->traverse_order()); + return ret; +} + // Flatten a struct construction expression. Store the values into // temporaries in case they need interface conversion. @@ -13032,6 +13081,20 @@ Fixed_array_construction_expression::Fix type, indexes, vals, location) { go_assert(type->array_type() != NULL && !type->is_slice_type()); } + +// Copy. + +Expression* +Fixed_array_construction_expression::do_copy() +{ + Type* t = this->type()->copy_expressions(); + return new Fixed_array_construction_expression(t, this->indexes(), + (this->vals() == NULL + ? NULL + : this->vals()->copy()), + this->location()); +} + // Return the backend representation for constructing a fixed array. Bexpression* @@ -13166,6 +13229,19 @@ dump_slice_storage_expression(Ast_dump_c ast_dump_context->dump_expression(this->slice_storage_); } +// Copy. + +Expression* +Slice_construction_expression::do_copy() +{ + return new Slice_construction_expression(this->type()->copy_expressions(), + this->indexes(), + (this->vals() == NULL + ? NULL + : this->vals()->copy()), + this->location()); +} + // Return the backend representation for constructing a slice. Bexpression* @@ -13379,6 +13455,18 @@ Map_construction_expression::do_check_ty } } +// Copy. + +Expression* +Map_construction_expression::do_copy() +{ + return new Map_construction_expression(this->type_->copy_expressions(), + (this->vals_ == NULL + ? NULL + : this->vals_->copy()), + this->location()); +} + // Return the backend representation for constructing a map. Bexpression* @@ -14058,6 +14146,23 @@ Composite_literal_expression::lower_map( return new Map_construction_expression(type, this->vals_, location); } +// Copy. + +Expression* +Composite_literal_expression::do_copy() +{ + Composite_literal_expression* ret = + new Composite_literal_expression(this->type_->copy_expressions(), + this->depth_, this->has_keys_, + (this->vals_ == NULL + ? NULL + : this->vals_->copy()), + this->all_are_names_, + this->location()); + ret->key_path_ = this->key_path_; + return ret; +} + // Dump ast representation for a composite literal expression. void @@ -14234,6 +14339,16 @@ Type_guard_expression::do_check_types(Go } } +// Copy. + +Expression* +Type_guard_expression::do_copy() +{ + return new Type_guard_expression(this->expr_->copy(), + this->type_->copy_expressions(), + this->location()); +} + // Return the backend representation for a type guard expression. Bexpression* @@ -14961,7 +15076,8 @@ class Slice_value_expression : public Ex Expression* do_copy() { - return new Slice_value_expression(this->type_, this->valptr_->copy(), + return new Slice_value_expression(this->type_->copy_expressions(), + this->valptr_->copy(), this->len_->copy(), this->cap_->copy(), this->location()); } @@ -15222,7 +15338,7 @@ class Interface_value_expression : publi Expression* do_copy() { - return new Interface_value_expression(this->type_, + return new Interface_value_expression(this->type_->copy_expressions(), this->first_field_->copy(), this->obj_->copy(), this->location()); } @@ -15317,7 +15433,9 @@ class Interface_mtable_expression : publ Expression* do_copy() { - return new Interface_mtable_expression(this->itype_, this->type_, + Interface_type* itype = this->itype_->copy_expressions()->interface_type(); + return new Interface_mtable_expression(itype, + this->type_->copy_expressions(), this->is_pointer_, this->location()); } @@ -15805,6 +15923,13 @@ Backend_expression::do_traverse(Traverse return TRAVERSE_CONTINUE; } +Expression* +Backend_expression::do_copy() +{ + return new Backend_expression(this->bexpr_, this->type_->copy_expressions(), + this->location()); +} + void Backend_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 257377) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -1664,11 +1664,7 @@ class Type_conversion_expression : publi do_check_types(Gogo*); Expression* - do_copy() - { - return new Type_conversion_expression(this->type_, this->expr_->copy(), - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context* context); @@ -1720,12 +1716,7 @@ class Unsafe_type_conversion_expression { this->expr_->determine_type_no_context(); } Expression* - do_copy() - { - return new Unsafe_type_conversion_expression(this->type_, - this->expr_->copy(), - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*); @@ -3430,19 +3421,7 @@ class Composite_literal_expression : pub do_lower(Gogo*, Named_object*, Statement_inserter*, int); Expression* - do_copy() - { - Composite_literal_expression *ret = - new Composite_literal_expression(this->type_, this->depth_, - this->has_keys_, - (this->vals_ == NULL - ? NULL - : this->vals_->copy()), - this->all_are_names_, - this->location()); - ret->key_path_ = this->key_path_; - return ret; - } + do_copy(); void do_dump_expression(Ast_dump_context*) const; @@ -3556,18 +3535,7 @@ class Struct_construction_expression : p do_check_types(Gogo*); Expression* - do_copy() - { - Struct_construction_expression* ret = - new Struct_construction_expression(this->type_, - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); - if (this->traverse_order() != NULL) - ret->set_traverse_order(this->traverse_order()); - return ret; - } + do_copy(); Expression* do_flatten(Gogo*, Named_object*, Statement_inserter*); @@ -3671,15 +3639,7 @@ class Fixed_array_construction_expressio protected: Expression* - do_copy() - { - return new Fixed_array_construction_expression(this->type(), - this->indexes(), - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*); @@ -3712,14 +3672,7 @@ class Slice_construction_expression : pu do_traverse(Traverse* traverse); Expression* - do_copy() - { - return new Slice_construction_expression(this->type(), this->indexes(), - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*); @@ -3778,14 +3731,7 @@ class Map_construction_expression : publ do_check_types(Gogo*); Expression* - do_copy() - { - return new Map_construction_expression(this->type_, - (this->vals_ == NULL - ? NULL - : this->vals_->copy()), - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*); @@ -3846,11 +3792,7 @@ class Type_guard_expression : public Exp do_check_types(Gogo*); Expression* - do_copy() - { - return new Type_guard_expression(this->expr_->copy(), this->type_, - this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*); @@ -4102,10 +4044,7 @@ class Backend_expression : public Expres { } Expression* - do_copy() - { - return new Backend_expression(this->bexpr_, this->type_, this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*) Index: gcc/go/gofrontend/parse.cc =================================================================== --- gcc/go/gofrontend/parse.cc (revision 257378) +++ gcc/go/gofrontend/parse.cc (working copy) @@ -50,7 +50,6 @@ Parse::Parse(Lex* lex, Gogo* gogo) gogo_(gogo), break_stack_(NULL), continue_stack_(NULL), - iota_(0), enclosing_vars_() { } @@ -1407,19 +1406,20 @@ Parse::const_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_CONST)); this->advance_token(); - this->reset_iota(); + int iota = 0; Type* last_type = NULL; Expression_list* last_expr_list = NULL; if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - this->const_spec(&last_type, &last_expr_list); + this->const_spec(iota, &last_type, &last_expr_list); else { this->advance_token(); while (!this->peek_token()->is_op(OPERATOR_RPAREN)) { - this->const_spec(&last_type, &last_expr_list); + this->const_spec(iota, &last_type, &last_expr_list); + ++iota; if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) this->advance_token(); else if (!this->peek_token()->is_op(OPERATOR_RPAREN)) @@ -1440,7 +1440,7 @@ Parse::const_decl() // ConstSpec = IdentifierList [ [ CompleteType ] "=" ExpressionList ] . void -Parse::const_spec(Type** last_type, Expression_list** last_expr_list) +Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list) { Typed_identifier_list til; this->identifier_list(&til); @@ -1492,7 +1492,7 @@ Parse::const_spec(Type** last_type, Expr pi->set_type(type); if (!Gogo::is_sink_name(pi->name())) - this->gogo_->add_constant(*pi, *pe, this->iota_value()); + this->gogo_->add_constant(*pi, *pe, iota); else { static int count; @@ -1500,15 +1500,13 @@ Parse::const_spec(Type** last_type, Expr snprintf(buf, sizeof buf, ".$sinkconst%d", count); ++count; Typed_identifier ti(std::string(buf), type, pi->location()); - Named_object* no = this->gogo_->add_constant(ti, *pe, this->iota_value()); + Named_object* no = this->gogo_->add_constant(ti, *pe, iota); no->const_value()->set_is_sink(); } } if (pe != expr_list->end()) go_error_at(this->location(), "too many initializers"); - this->increment_iota(); - return; } @@ -5838,30 +5836,6 @@ Parse::program() } } -// Reset the current iota value. - -void -Parse::reset_iota() -{ - this->iota_ = 0; -} - -// Return the current iota value. - -int -Parse::iota_value() -{ - return this->iota_; -} - -// Increment the current iota value. - -void -Parse::increment_iota() -{ - ++this->iota_; -} - // Skip forward to a semicolon or OP. OP will normally be // OPERATOR_RPAREN or OPERATOR_RCURLY. If we find a semicolon, move // past it and return. If we find OP, it will be the next token to Index: gcc/go/gofrontend/parse.h =================================================================== --- gcc/go/gofrontend/parse.h (revision 257357) +++ gcc/go/gofrontend/parse.h (working copy) @@ -7,7 +7,6 @@ #ifndef GO_PARSE_H #define GO_PARSE_H -class Set_iota_traverse; class Lex; class Gogo; class Named_object; @@ -185,7 +184,7 @@ class Parse void decl(void (Parse::*)(void*, unsigned int), void*, unsigned int pragmas); void list(void (Parse::*)(void*, unsigned int), void*, bool); void const_decl(); - void const_spec(Type**, Expression_list**); + void const_spec(int, Type**, Expression_list**); void type_decl(unsigned int pragmas); void type_spec(void*, unsigned int pragmas); void var_decl(); @@ -280,10 +279,6 @@ class Parse void import_decl(); void import_spec(void*, unsigned int pragmas); - void reset_iota(); - int iota_value(); - void increment_iota(); - // Skip past an error looking for a semicolon or OP. Return true if // all is well, false if we found EOF. bool @@ -319,8 +314,6 @@ class Parse Bc_stack* break_stack_; // A stack of statements for which continue may be used. Bc_stack* continue_stack_; - // The current iota value. - int iota_; // References from the local function to variables defined in // enclosing functions. Enclosing_vars enclosing_vars_; Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 257357) +++ gcc/go/gofrontend/types.cc (working copy) @@ -868,6 +868,68 @@ Type::are_convertible(const Type* lhs, c return false; } +// Copy expressions if it may change the size. +// +// The only type that has an expression is an array type. The only +// types whose size can be changed by the size of an array type are an +// array type itself, or a struct type with an array field. +Type* +Type::copy_expressions() +{ + // This is run during parsing, so types may not be valid yet. + // We only have to worry about array type literals. + switch (this->classification_) + { + default: + return this; + + case TYPE_ARRAY: + { + Array_type* at = this->array_type(); + if (at->length() == NULL) + return this; + Expression* len = at->length()->copy(); + if (at->length() == len) + return this; + return Type::make_array_type(at->element_type(), len); + } + + case TYPE_STRUCT: + { + Struct_type* st = this->struct_type(); + const Struct_field_list* sfl = st->fields(); + if (sfl == NULL) + return this; + bool changed = false; + Struct_field_list *nsfl = new Struct_field_list(); + for (Struct_field_list::const_iterator pf = sfl->begin(); + pf != sfl->end(); + ++pf) + { + Type* ft = pf->type()->copy_expressions(); + Struct_field nf(Typed_identifier((pf->is_anonymous() + ? "" + : pf->field_name()), + ft, + pf->location())); + if (pf->has_tag()) + nf.set_tag(pf->tag()); + nsfl->push_back(nf); + if (ft != pf->type()) + changed = true; + } + if (!changed) + { + delete(nsfl); + return this; + } + return Type::make_struct_type(nsfl, st->location()); + } + } + + go_unreachable(); +} + // Return a hash code for the type to be used for method lookup. unsigned int Index: gcc/go/gofrontend/types.h =================================================================== --- gcc/go/gofrontend/types.h (revision 257357) +++ gcc/go/gofrontend/types.h (working copy) @@ -916,6 +916,15 @@ class Type is_unsafe_pointer_type() const { return this->points_to() != NULL && this->points_to()->is_void_type(); } + // Return a version of this type with any expressions copied, but + // only if copying the expressions will affect the size of the type. + // If there are no such expressions in the type (expressions can + // only occur in array types), just return the same type. If any + // expressions can not affect the size of the type, just return the + // same type. + Type* + copy_expressions(); + // Look for field or method NAME for TYPE. Return an expression for // it, bound to EXPR. static Expression* @@ -2444,6 +2453,11 @@ class Struct_type : public Type field_count() const { return this->fields_->size(); } + // Location of struct definition. + Location + location() const + { return this->location_; } + // Push a new field onto the end of the struct. This is used when // building a closure variable. void