summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-08-02 16:27:42 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-08-02 16:27:42 +0000
commit8d46b942590f1f4dbe71f0c7ec68ebcbc41b28f8 (patch)
tree7718106385533dcedcd3b1e9a3428db014fbcda6
parent5f6a9dd8d086ab342d8de535712fc566e5414802 (diff)
downloadgcc-8d46b942590f1f4dbe71f0c7ec68ebcbc41b28f8.tar.gz
compiler: only finalize embedded fields before finalizing methods
When finalizing the methods of a named struct type, we used to finalize all the field types first. That can fail if the field types refer indirectly to the named type. Change it to just finalize the embedded field types first, and the rest of the fields later. Fixes golang/go#21253 Reviewed-on: https://go-review.googlesource.com/52570 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@250833 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/gofrontend/gogo.cc41
1 files changed, 34 insertions, 7 deletions
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index a190917512a..4a932e4600e 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -2973,26 +2973,53 @@ Finalize_methods::type(Type* t)
case Type::TYPE_NAMED:
{
- // We have to finalize the methods of the real type first.
- // But if the real type is a struct type, then we only want to
- // finalize the methods of the field types, not of the struct
- // type itself. We don't want to add methods to the struct,
- // since it has a name.
Named_type* nt = t->named_type();
Type* rt = nt->real_type();
if (rt->classification() != Type::TYPE_STRUCT)
{
+ // Finalize the methods of the real type first.
if (Type::traverse(rt, this) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
+
+ // Finalize the methods of this type.
+ nt->finalize_methods(this->gogo_);
}
else
{
+ // We don't want to finalize the methods of a named struct
+ // type, as the methods should be attached to the named
+ // type, not the struct type. We just want to finalize
+ // the field types.
+ //
+ // It is possible that a field type refers indirectly to
+ // this type, such as via a field with function type with
+ // an argument or result whose type is this type. To
+ // avoid the cycle, first finalize the methods of any
+ // embedded types, which are the only types we need to
+ // know to finalize the methods of this type.
+ const Struct_field_list* fields = rt->struct_type()->fields();
+ if (fields != NULL)
+ {
+ for (Struct_field_list::const_iterator pf = fields->begin();
+ pf != fields->end();
+ ++pf)
+ {
+ if (pf->is_anonymous())
+ {
+ if (Type::traverse(pf->type(), this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
+ }
+ }
+
+ // Finalize the methods of this type.
+ nt->finalize_methods(this->gogo_);
+
+ // Finalize all the struct fields.
if (rt->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
- nt->finalize_methods(this->gogo_);
-
// If this type is defined in a different package, then finalize the
// types of all the methods, since we won't see them otherwise.
if (nt->named_object()->package() != NULL && nt->has_any_methods())