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: