diff options
author | Martin Liska <mliska@suse.cz> | 2022-06-17 13:05:50 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-06-17 13:05:50 +0200 |
commit | 910ef4ff32f3a53dbd12445e1eb8c5349d047140 (patch) | |
tree | ef0772e400ad08ab2bef318992cc2c1bf6fb5b7e /gcc/go | |
parent | cad2e08f6c249937e10ad5ae0d4a117923979efb (diff) | |
parent | 94018fd2675190a4353cb199da4957538f070886 (diff) | |
download | gcc-910ef4ff32f3a53dbd12445e1eb8c5349d047140.zip gcc-910ef4ff32f3a53dbd12445e1eb8c5349d047140.tar.gz gcc-910ef4ff32f3a53dbd12445e1eb8c5349d047140.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 2 | ||||
-rw-r--r-- | gcc/go/go-lang.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 343 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 29 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 16 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 37 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 38 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 11 |
11 files changed, 380 insertions, 128 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index f50a60b7..5fdf423 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,12 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * go-lang.cc (go_get_sarif_source_language): New. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (go.tags): Look at *.cc. + 2022-02-13 Ian Lance Taylor <iant@golang.org> * gospec.cc: Revert 2022-02-09 change: diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 31c6773..0e81268 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -133,7 +133,7 @@ go.srcinfo: doc/gccgo.info go.srcextra: go.tags: force cd $(srcdir)/go; \ - $(ETAGS) -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \ + $(ETAGS) -o TAGS.sub *.cc *.h gofrontend/*.h gofrontend/*.cc; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub go.man: doc/gccgo.1 go.srcman: doc/gccgo.1 diff --git a/gcc/go/go-lang.cc b/gcc/go/go-lang.cc index c8365d2..84cd623 100644 --- a/gcc/go/go-lang.cc +++ b/gcc/go/go-lang.cc @@ -545,6 +545,15 @@ go_langhook_eh_personality (void) return personality_decl; } +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +go_get_sarif_source_language (const char *) +{ + return "go"; +} + /* Functions called directly by the generic backend. */ tree @@ -615,6 +624,7 @@ go_localize_identifier (const char *ident) #undef LANG_HOOKS_GETDECLS #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_EH_PERSONALITY +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE #define LANG_HOOKS_NAME "GNU Go" #define LANG_HOOKS_INIT go_langhook_init @@ -631,6 +641,7 @@ go_localize_identifier (const char *ident) #define LANG_HOOKS_GETDECLS go_langhook_getdecls #define LANG_HOOKS_GIMPLIFY_EXPR go_langhook_gimplify_expr #define LANG_HOOKS_EH_PERSONALITY go_langhook_eh_personality +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE go_get_sarif_source_language struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index d9b1269..0cda305 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5042f7efbdb2d64537dfef53a19e96ee5ec4db2d +8db6b78110f84e22c409f334aeaefb80a8b39917 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/export.cc b/gcc/go/gofrontend/export.cc index 3d11334..a30b11a 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -124,6 +124,11 @@ class Collect_export_references : public Traverse void prepare_types(const std::vector<Named_object*>& sorted_exports); + // Third entry point (called after the method above), to find + // all types in expressions referenced by exports. + void + prepare_expressions(const std::vector<Named_object*>& sorted_exports); + protected: // Override of parent class method. int @@ -281,6 +286,28 @@ Collect_export_references::expression(Expression** pexpr) return TRAVERSE_CONTINUE; } +// Collect up the set of types mentioned in expressions of things we're exporting, +// and collect all the packages encountered during type traversal, to make sure +// we can declare things referered to indirectly (for example, in the body of an +// exported inline function from another package). + +void +Collect_export_references::prepare_expressions(const std::vector<Named_object*>& sorted_exports) +{ + for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); + p != sorted_exports.end(); + ++p) + { + Named_object* no = *p; + if (no->classification() == Named_object::NAMED_OBJECT_CONST) + { + Expression* e = no->const_value()->expr(); + if (e != NULL) + Expression::traverse(&e, this); + } + } +} + // Collect up the set of types mentioned in things we're exporting, and collect // all the packages encountered during type traversal, to make sure we can // declare things referered to indirectly (for example, in the body of an @@ -360,16 +387,6 @@ Collect_export_references::type(Type* type) if (type->is_abstract()) return TRAVERSE_SKIP_COMPONENTS; - // For interfaces make sure that embedded methods are sorted, since the - // comparison function we use for indexing types relies on it (this call has - // to happen before the record_type call below). - if (type->classification() == Type::TYPE_INTERFACE) - { - Interface_type* it = type->interface_type(); - if (it != NULL) - it->sort_embedded(); - } - if (!this->exp_->record_type(type)) { // We've already seen this type. @@ -501,6 +518,11 @@ should_export(Named_object* no) return true; } +// Compare Typed_identifier_list's. + +static int +compare_til(const Typed_identifier_list*, const Typed_identifier_list*); + // A functor to sort Named_object pointers by name. struct Sort_bindings @@ -514,10 +536,57 @@ struct Sort_bindings return true; if (n2->package() == NULL) return false; - return n1->package()->pkgpath() < n2->package()->pkgpath(); + + // Make sure we don't see the same pkgpath twice. + const std::string& p1(n1->package()->pkgpath()); + const std::string& p2(n2->package()->pkgpath()); + go_assert(p1 != p2); + + return p1 < p2; } - return n1->name() < n2->name(); + if (n1->name() != n2->name()) + return n1->name() < n2->name(); + + // We shouldn't see the same name twice, but it can happen for + // nested type names. + + go_assert(n1->is_type() && n2->is_type()); + + unsigned int ind1; + const Named_object* g1 = n1->type_value()->in_function(&ind1); + unsigned int ind2; + const Named_object* g2 = n2->type_value()->in_function(&ind2); + + if (g1 == NULL) + { + go_assert(g2 != NULL); + return true; + } + else if (g2 == NULL) + return false; + else if (g1 == g2) + { + go_assert(ind1 != ind2); + return ind1 < ind2; + } + else if ((g1->package() != g2->package()) || (g1->name() != g2->name())) + return Sort_bindings()(g1, g2); + else + { + // This case can happen if g1 or g2 is a method. + if (g1 != NULL && g1->func_value()->is_method()) + { + const Typed_identifier* r = g1->func_value()->type()->receiver(); + g1 = r->type()->named_type()->named_object(); + } + if (g2 != NULL && g2->func_value()->is_method()) + { + const Typed_identifier* r = g2->func_value()->type()->receiver(); + g2 = r->type()->named_type()->named_object(); + } + return Sort_bindings()(g1, g2); + } } }; @@ -528,17 +597,20 @@ struct Sort_types bool operator()(const Type* t1, const Type* t2) const { + t1 = t1->forwarded(); + t2 = t2->forwarded(); + const Named_type* nt1 = t1->named_type(); const Named_type* nt2 = t2->named_type(); if (nt1 != NULL) { - if (nt2 != NULL) - { - Sort_bindings sb; - return sb(nt1->named_object(), nt2->named_object()); - } - else - return true; + if (nt2 != NULL) + { + Sort_bindings sb; + return sb(nt1->named_object(), nt2->named_object()); + } + else + return true; } else if (nt2 != NULL) return false; @@ -549,10 +621,218 @@ struct Sort_types gogo->type_descriptor_backend_name(t1, NULL, &b1); Backend_name b2; gogo->type_descriptor_backend_name(t2, NULL, &b2); - return b1.name() < b2.name(); + + std::string n1 = b1.name(); + std::string n2 = b2.name(); + if (n1 != n2) + return n1 < n2; + + // We should never see equal types here. If we do, we may not + // generate an identical output file for identical input. But the + // backend names can be equal because we want to treat aliases + // differently while type_descriptor_backend_name does not. In + // that case we need to traverse the type elements. + + // t1 == t2 in case std::sort compares elements to themselves. + if (t1 == t2) + return false; + + Sort_types sort; + Type_alias_identical identical; + go_assert(!identical(t1, t2)); + + switch (t1->classification()) + { + case Type::TYPE_ERROR: + return false; + + case Type::TYPE_VOID: + case Type::TYPE_BOOLEAN: + case Type::TYPE_INTEGER: + case Type::TYPE_FLOAT: + case Type::TYPE_COMPLEX: + case Type::TYPE_STRING: + case Type::TYPE_SINK: + case Type::TYPE_NIL: + case Type::TYPE_CALL_MULTIPLE_RESULT: + case Type::TYPE_NAMED: + case Type::TYPE_FORWARD: + default: + go_unreachable(); + + case Type::TYPE_FUNCTION: + { + const Function_type* ft1 = t1->function_type(); + const Function_type* ft2 = t2->function_type(); + const Typed_identifier* r1 = ft1->receiver(); + const Typed_identifier* r2 = ft2->receiver(); + if (r1 == NULL) + go_assert(r2 == NULL); + else + { + go_assert(r2 != NULL); + const Type* rt1 = r1->type()->forwarded(); + const Type* rt2 = r2->type()->forwarded(); + if (!identical(rt1, rt2)) + return sort(rt1, rt2); + } + + const Typed_identifier_list* p1 = ft1->parameters(); + const Typed_identifier_list* p2 = ft2->parameters(); + if (p1 == NULL || p1->empty()) + go_assert(p2 == NULL || p2->empty()); + else + { + go_assert(p2 != NULL && !p2->empty()); + int i = compare_til(p1, p2); + if (i < 0) + return false; + else if (i > 0) + return true; + } + + p1 = ft1->results(); + p2 = ft2->results(); + if (p1 == NULL || p1->empty()) + go_assert(p2 == NULL || p2->empty()); + else + { + go_assert(p2 != NULL && !p2->empty()); + int i = compare_til(p1, p2); + if (i < 0) + return false; + else if (i > 0) + return true; + } + + go_unreachable(); + } + + case Type::TYPE_POINTER: + { + const Type* p1 = t1->points_to()->forwarded(); + const Type* p2 = t2->points_to()->forwarded(); + go_assert(!identical(p1, p2)); + return sort(p1, p2); + } + + case Type::TYPE_STRUCT: + { + const Struct_type* s1 = t1->struct_type(); + const Struct_type* s2 = t2->struct_type(); + const Struct_field_list* f1 = s1->fields(); + const Struct_field_list* f2 = s2->fields(); + go_assert(f1 != NULL && f2 != NULL); + Struct_field_list::const_iterator p1 = f1->begin(); + Struct_field_list::const_iterator p2 = f2->begin(); + for (; p2 != f2->end(); ++p1, ++p2) + { + go_assert(p1 != f1->end()); + go_assert(p1->field_name() == p2->field_name()); + go_assert(p1->is_anonymous() == p2->is_anonymous()); + const Type* ft1 = p1->type()->forwarded(); + const Type* ft2 = p2->type()->forwarded(); + if (!identical(ft1, ft2)) + return sort(ft1, ft2); + } + go_assert(p1 == f1->end()); + go_unreachable(); + } + + case Type::TYPE_ARRAY: + { + const Type* e1 = t1->array_type()->element_type()->forwarded(); + const Type* e2 = t2->array_type()->element_type()->forwarded(); + go_assert(!identical(e1, e2)); + return sort(e1, e2); + } + + case Type::TYPE_MAP: + { + const Map_type* m1 = t1->map_type(); + const Map_type* m2 = t2->map_type(); + const Type* k1 = m1->key_type()->forwarded(); + const Type* k2 = m2->key_type()->forwarded(); + if (!identical(k1, k2)) + return sort(k1, k2); + const Type* v1 = m1->val_type()->forwarded(); + const Type* v2 = m2->val_type()->forwarded(); + go_assert(!identical(v1, v2)); + return sort(v1, v2); + } + + case Type::TYPE_CHANNEL: + { + const Type* e1 = t1->channel_type()->element_type()->forwarded(); + const Type* e2 = t2->channel_type()->element_type()->forwarded(); + go_assert(!identical(e1, e2)); + return sort(e1, e2); + } + + case Type::TYPE_INTERFACE: + { + const Interface_type* it1 = t1->interface_type(); + const Interface_type* it2 = t2->interface_type(); + const Typed_identifier_list* m1 = it1->local_methods(); + const Typed_identifier_list* m2 = it2->local_methods(); + + // We know the full method lists are the same, because the + // mangled type names were the same, but here we are looking + // at the local method lists, which include embedded + // interfaces, and we can have an embedded empty interface. + if (m1 == NULL || m1->empty()) + { + go_assert(m2 != NULL && !m2->empty()); + return true; + } + else if (m2 == NULL || m2->empty()) + { + go_assert(m1 != NULL && !m1->empty()); + return false; + } + + int i = compare_til(m1, m2); + if (i < 0) + return false; + else if (i > 0) + return true; + else + go_unreachable(); + } + } } }; +// Compare Typed_identifier_list's with Sort_types, returning -1, 0, +1. + +static int +compare_til( + const Typed_identifier_list* til1, + const Typed_identifier_list* til2) +{ + Type_alias_identical identical; + Sort_types sort; + Typed_identifier_list::const_iterator p1 = til1->begin(); + Typed_identifier_list::const_iterator p2 = til2->begin(); + for (; p2 != til2->end(); ++p1, ++p2) + { + if (p1 == til1->end()) + return -1; + const Type* t1 = p1->type()->forwarded(); + const Type* t2 = p2->type()->forwarded(); + if (!identical(t1, t2)) + { + if (sort(t1, t2)) + return -1; + else + return +1; + } + } + if (p1 != til1->end()) + return +1; + return 0; +} + // Export those identifiers marked for exporting. void @@ -638,6 +918,7 @@ Export::export_globals(const std::string& package_name, // Collect up the set of types mentioned in things we're exporting, // and any packages that may be referred to indirectly. collect.prepare_types(sorted_exports); + collect.prepare_expressions(sorted_exports); // Assign indexes to all exported types and types referenced by // things we're exporting. Return value is index of first non-exported @@ -714,17 +995,9 @@ bool Export::record_type(Type* type) { type = type->forwarded(); - std::pair<Type_refs::iterator, bool> ins = this->impl_->type_refs.insert(std::make_pair(type, 0)); - if (!ins.second) - { - // We've already seen this type. - return false; - } - ins.first->second = 0; - - return true; + return ins.second; } // Assign the specified type an index. @@ -733,13 +1006,12 @@ void Export::set_type_index(const Type* type) { type = type->forwarded(); - std::pair<Type_refs::iterator, bool> ins = - this->impl_->type_refs.insert(std::make_pair(type, 0)); - go_assert(!ins.second); + Type_refs::iterator p = this->impl_->type_refs.find(type); + go_assert(p != this->impl_->type_refs.end()); int index = this->type_index_; ++this->type_index_; - go_assert(ins.first->second == 0); - ins.first->second = index; + go_assert(p->second == 0); + p->second = index; } // This helper assigns type indices to all types mentioned directly or @@ -758,9 +1030,6 @@ Export::assign_type_indices(const std::vector<Named_object*>& sorted_exports) { if (!(*p)->is_type()) continue; - Interface_type* it = (*p)->type_value()->interface_type(); - if (it != NULL) - it->sort_embedded(); this->record_type((*p)->type_value()); this->set_type_index((*p)->type_value()); } diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 1b3b3bf..734ecb9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -7671,8 +7671,7 @@ Expression::comparison(Translate_context* context, Type* result_type, && left_type->array_type()->length() == NULL) { Array_type* at = left_type->array_type(); - bool is_lvalue = false; - left = at->get_value_pointer(context->gogo(), left, is_lvalue); + left = at->get_value_pointer(context->gogo(), left); } else if (left_type->interface_type() != NULL) { @@ -9276,7 +9275,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type()); Expression* a1 = Expression::make_type_descriptor(element_type, loc); Expression* a2 = Expression::make_temporary_reference(s1tmp, loc); - a2 = slice_type->array_type()->get_value_pointer(gogo, a2, false); + a2 = slice_type->array_type()->get_value_pointer(gogo, a2); a2 = Expression::make_cast(unsafe_ptr_type, a2, loc); Expression* a3 = Expression::make_temporary_reference(l1tmp, loc); Expression* a4 = Expression::make_temporary_reference(c1tmp, loc); @@ -13848,9 +13847,8 @@ Array_index_expression::do_get_backend(Translate_context* context) } else { - Expression* valptr = - array_type->get_value_pointer(gogo, this->array_, - this->is_lvalue_); + Expression* valptr = array_type->get_value_pointer(gogo, + this->array_); Bexpression* ptr = valptr->get_backend(context); ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc); @@ -13891,8 +13889,7 @@ Array_index_expression::do_get_backend(Translate_context* context) Bexpression* offset = gogo->backend()->conditional_expression(bfn, int_btype, cond, zero, start, loc); - Expression* valptr = array_type->get_value_pointer(gogo, this->array_, - this->is_lvalue_); + Expression* valptr = array_type->get_value_pointer(gogo, this->array_); Bexpression* val = valptr->get_backend(context); val = gogo->backend()->pointer_offset_expression(val, offset, loc); @@ -17266,6 +17263,8 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, Location location = this->location(); Unordered_map(unsigned int, std::vector<Expression*>) st; Unordered_map(unsigned int, std::vector<Expression*>) nt; + bool saw_false = false; + bool saw_true = false; if (this->vals_ != NULL) { if (!this->has_keys_) @@ -17300,6 +17299,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, continue; std::string sval; Numeric_constant nval; + bool bval; if ((*p)->string_constant_value(&sval)) // Check string keys. { unsigned int h = Gogo::hash_string(sval, 0); @@ -17373,6 +17373,19 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, mit->second.push_back(*p); } } + else if ((*p)->boolean_constant_value(&bval)) + { + if ((bval && saw_true) || (!bval && saw_false)) + { + go_error_at((*p)->location(), + "duplicate key in map literal"); + return Expression::make_error(location); + } + if (bval) + saw_true = true; + else + saw_false = true; + } } } diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 92e8d8d..707c193 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -3055,7 +3055,7 @@ class Array_index_expression : public Expression Expression* end, Expression* cap, Location location) : Expression(EXPRESSION_ARRAY_INDEX, location), array_(array), start_(start), end_(end), cap_(cap), type_(NULL), - is_lvalue_(false), needs_bounds_check_(true), is_flattened_(false) + needs_bounds_check_(true), is_flattened_(false) { } // Return the array. @@ -3087,18 +3087,6 @@ class Array_index_expression : public Expression end() const { return this->end_; } - // Return whether this array index expression appears in an lvalue - // (left hand side of assignment) context. - bool - is_lvalue() const - { return this->is_lvalue_; } - - // Update this array index expression to indicate that it appears - // in a left-hand-side or lvalue context. - void - set_is_lvalue() - { this->is_lvalue_ = true; } - void set_needs_bounds_check(bool b) { this->needs_bounds_check_ = b; } @@ -3174,8 +3162,6 @@ class Array_index_expression : public Expression Expression* cap_; // The type of the expression. Type* type_; - // Whether expr appears in an lvalue context. - bool is_lvalue_; // Whether bounds check is needed. bool needs_bounds_check_; // Whether this has already been flattened. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 30d5c9f..d35c6ba 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1612,31 +1612,16 @@ Gogo::write_globals() // The initializer is constant if it is the zero-value of the // variable's type or if the initial value is an immutable value // that is not copied to the heap. - Expression* init = var->init(); - - // If we see "a = b; b = x", and x is a static - // initializer, just set a to x. - while (init != NULL && init->var_expression() != NULL) - { - Named_object* ino = init->var_expression()->named_object(); - if (!ino->is_variable() || ino->package() != NULL) - break; - Expression* ino_init = ino->var_value()->init(); - if (ino->var_value()->has_pre_init() - || ino_init == NULL - || !ino_init->is_static_initializer()) - break; - init = ino_init; - } - - bool is_static_initializer; - if (init == NULL) + bool is_static_initializer = false; + if (var->init() == NULL) is_static_initializer = true; else { Type* var_type = var->type(); - init = Expression::make_cast(var_type, init, var->location()); - is_static_initializer = init->is_static_initializer(); + Expression* init = var->init(); + Expression* init_cast = + Expression::make_cast(var_type, init, var->location()); + is_static_initializer = init_cast->is_static_initializer(); } // Non-constant variable initializations might need to create @@ -1655,15 +1640,7 @@ Gogo::write_globals() } var_init_fn = init_fndecl; } - - Bexpression* var_binit; - if (init == NULL) - var_binit = NULL; - else - { - Translate_context context(this, var_init_fn, NULL, NULL); - var_binit = init->get_backend(&context); - } + Bexpression* var_binit = var->get_init(this, var_init_fn); if (var_binit == NULL) ; diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 95fa3c4..b3db843 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1260,6 +1260,16 @@ Assignment_operation_statement::do_lower(Gogo*, Named_object*, Move_ordered_evals moe(b); this->lhs_->traverse_subexpressions(&moe); + // We can still be left with subexpressions that have to be loaded + // even if they don't have side effects themselves, in case the RHS + // changes variables named on the LHS. + int i; + if (this->lhs_->must_eval_subexpressions_in_order(&i)) + { + Move_subexpressions ms(i, b); + this->lhs_->traverse_subexpressions(&ms); + } + Expression* lval = this->lhs_->copy(); Operator op; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 3de0bd3..eb3afd9 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -7815,7 +7815,7 @@ Array_type::finish_backend_element(Gogo* gogo) // Return an expression for a pointer to the values in ARRAY. Expression* -Array_type::get_value_pointer(Gogo*, Expression* array, bool is_lvalue) const +Array_type::get_value_pointer(Gogo*, Expression* array) const { if (this->length() != NULL) { @@ -7828,25 +7828,6 @@ Array_type::get_value_pointer(Gogo*, Expression* array, bool is_lvalue) const } // Slice. - - if (is_lvalue) - { - Temporary_reference_expression* tref = - array->temporary_reference_expression(); - Var_expression* ve = array->var_expression(); - if (tref != NULL) - { - tref = tref->copy()->temporary_reference_expression(); - tref->set_is_lvalue(); - array = tref; - } - else if (ve != NULL) - { - ve = new Var_expression(ve->named_object(), ve->location()); - array = ve; - } - } - return Expression::make_slice_info(array, Expression::SLICE_INFO_VALUE_POINTER, array->location()); @@ -9050,6 +9031,9 @@ Interface_type::finalize_methods() if (this->parse_methods_ == NULL) return; + // The exporter uses parse_methods_. + this->parse_methods_->sort_by_name(); + this->all_methods_ = new Typed_identifier_list(); this->all_methods_->reserve(this->parse_methods_->size()); Typed_identifier_list inherit; @@ -9337,15 +9321,17 @@ Interface_type::is_compatible_for_assign(const Interface_type* t, // Hash code. unsigned int -Interface_type::do_hash_for_method(Gogo*, int) const +Interface_type::do_hash_for_method(Gogo*, int flags) const { go_assert(this->methods_are_finalized_); + Typed_identifier_list* methods = (((flags & COMPARE_EMBEDDED_INTERFACES) != 0) + ? this->parse_methods_ + : this->all_methods_); unsigned int ret = 0; - if (this->all_methods_ != NULL) + if (methods != NULL) { - for (Typed_identifier_list::const_iterator p = - this->all_methods_->begin(); - p != this->all_methods_->end(); + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); ++p) { ret = Gogo::hash_string(p->name(), ret); @@ -11905,7 +11891,7 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, need_stub = true; if (!in_heap && !m->is_value_method()) need_stub = true; - if (!need_stub) + if (!need_stub || m->is_ambiguous()) continue; Type* receiver_type = const_cast<Type*>(type); diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index c55345a..49404bd 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2800,7 +2800,7 @@ class Array_type : public Type // Return an expression for the pointer to the values in an array. Expression* - get_value_pointer(Gogo*, Expression* array, bool is_lvalue) const; + get_value_pointer(Gogo*, Expression* array) const; // Return an expression for the length of an array with this type. Expression* @@ -3272,15 +3272,6 @@ class Interface_type : public Type methods_are_finalized() const { return this->methods_are_finalized_; } - // Sort embedded interfaces by name. Needed when we are preparing - // to emit types into the export data. - void - sort_embedded() - { - if (parse_methods_ != NULL) - parse_methods_->sort_by_name(); - } - protected: int do_traverse(Traverse*); |