This patch to the Go frontend changes traversal to always traverse
method declarations (method definitions were already traversed).  This
removes one existing case that explicitly traversed method
declarations, in favor of the common approach.

Note that the gc Go compiler rejects method declarations, and maybe
the Go frontend should too.  But not today.

This avoids a compiler crash (https://gcc.gnu.org/PR117891) if there
are method declarations with types that require specific functions.  I
didn't bother with a test case because a program with method
declarations is almost certainly invalid anyhow.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
7a24c637d957df027b834bcc5c0517410c812e1f
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 3bd755ce515..d189a9c6df0 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-dfe585bf82380630697e96c249de825c5f655afe
+f4956f807f1a33e406cf1b3bf3479a9ac1c1015a
 
 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/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 8a833761a5f..3aad4194c62 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -3592,26 +3592,6 @@ Finalize_methods::type(Type* t)
              }
          }
 
-       // Finalize the types of all methods that are declared but not
-       // defined, since we won't see the declarations otherwise.
-       if (nt->named_object()->package() == NULL
-           && nt->local_methods() != NULL)
-         {
-           const Bindings* methods = nt->local_methods();
-           for (Bindings::const_declarations_iterator p =
-                  methods->begin_declarations();
-                p != methods->end_declarations();
-                p++)
-             {
-               if (p->second->is_function_declaration())
-                 {
-                   Type* mt = p->second->func_declaration_value()->type();
-                   if (Type::traverse(mt, this) == TRAVERSE_EXIT)
-                     return TRAVERSE_EXIT;
-                 }
-             }
-         }
-
        return TRAVERSE_SKIP_COMPONENTS;
       }
 
@@ -8790,7 +8770,35 @@ Named_object::traverse(Traverse* traverse, bool 
is_global)
 
     case Named_object::NAMED_OBJECT_TYPE:
       if ((traverse_mask & e_or_t) != 0)
-       t = Type::traverse(this->type_value(), traverse);
+       {
+         t = Type::traverse(this->type_value(), traverse);
+         if (t == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+
+         // Traverse the types of any local methods that are declared
+         // but not defined.  We will see defined methods as
+         // NAMED_OBJECT_FUNC, but we won't see methods that are only
+         // declared.
+         if (this->package_ == NULL
+             && this->type_value()->named_type()->local_methods() != NULL)
+           {
+             const Bindings* methods =
+               this->type_value()->named_type()->local_methods();
+             for (Bindings::const_declarations_iterator p =
+                    methods->begin_declarations();
+                  p != methods->end_declarations();
+                  ++p)
+               {
+                 if (p->second->is_function_declaration())
+                   {
+                     Type* mt = p->second->func_declaration_value()->type();
+                     if (Type::traverse(mt, traverse) == TRAVERSE_EXIT)
+                       return TRAVERSE_EXIT;
+                   }
+               }
+           }
+       }
+
       break;
 
     case Named_object::NAMED_OBJECT_PACKAGE:

Reply via email to