aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-06-17 13:05:50 +0200
committerMartin Liska <mliska@suse.cz>2022-06-17 13:05:50 +0200
commit910ef4ff32f3a53dbd12445e1eb8c5349d047140 (patch)
treeef0772e400ad08ab2bef318992cc2c1bf6fb5b7e /gcc/go
parentcad2e08f6c249937e10ad5ae0d4a117923979efb (diff)
parent94018fd2675190a4353cb199da4957538f070886 (diff)
downloadgcc-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/ChangeLog9
-rw-r--r--gcc/go/Make-lang.in2
-rw-r--r--gcc/go/go-lang.cc11
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/export.cc343
-rw-r--r--gcc/go/gofrontend/expressions.cc29
-rw-r--r--gcc/go/gofrontend/expressions.h16
-rw-r--r--gcc/go/gofrontend/gogo.cc37
-rw-r--r--gcc/go/gofrontend/statements.cc10
-rw-r--r--gcc/go/gofrontend/types.cc38
-rw-r--r--gcc/go/gofrontend/types.h11
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*);