From: Ian Lance Taylor Date: Mon, 5 Feb 2018 01:57:42 +0000 (+0000) Subject: compiler: update iota handling, fix using iota in array length X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5dfb4d0f3339595881fba857ab5a4b57c681a8e3;p=gcc.git compiler: update iota handling, fix using iota in array length CL 71750 changed the definition of how iota works. This patch updates gccgo for the new definition. We've 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. Fixes golang/go#22341 Reviewed-on: https://go-review.googlesource.com/91475 From-SVN: r257379 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c0f977a44c4..3588a8a7a6a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 3bcc5ae1471..8555c052980 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1928,10 +1928,16 @@ class Integer_expression : public Expression 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 Expression 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 Expression 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_types(Gogo*) 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_static_initializer() const 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_types(Gogo*) 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::Fixed_array_construction_expression( 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_context* ast_dump_context) const 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_types(Gogo*) } } +// 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(Gogo* gogo, Named_object* function, 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(Gogo*) } } +// 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 Expression 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 : public Expression 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 : public Expression 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 { diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 18fd91b054f..d16a284b6b0 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1664,11 +1664,7 @@ class Type_conversion_expression : public Expression 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 : public 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 : public Parser_expression 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 : public Expression, 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_expression : 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 : public Array_construction_expression 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 : public Expression 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 Expression 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 Expression { } Expression* - do_copy() - { - return new Backend_expression(this->bexpr_, this->type_, this->location()); - } + do_copy(); Bexpression* do_get_backend(Translate_context*) diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index cc3791bb84d..4891e758f79 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -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, Expression_list** last_expr_list) 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, Expression_list** last_expr_list) 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 diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 2ba84579e6c..f309ee05469 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -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_; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index ea9d81d4e24..34edf762835 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -868,6 +868,68 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) 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 diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 4e060a4db11..648773131ca 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -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