compiler: only finalize embedded fields before finalizing methods
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 2 Aug 2017 16:27:17 +0000 (16:27 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 2 Aug 2017 16:27:17 +0000 (16:27 +0000)
    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

From-SVN: r250832

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/gogo.cc

index 685cff9935bc6a6bb40e4dd28a749375cc8d2fc2..7c96176261b05f675dce37507a9ecf46c4064beb 100644 (file)
@@ -1,4 +1,4 @@
-f7c36b27a49131f60eedde260896d310d735d408
+c1ac6bc99f988633c6bc68a5ca9ffad3487750ef
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index ca4b454a2381a06f52b1b151d0b5066a7078a0dd..5dbe29da261a64ccc586172bd853daeacc9162ed 100644 (file)
@@ -3058,26 +3058,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())