This patch to the Go frontend fixes a bug in the handling of methods of embedded fields. If the same type was embedded in a struct at different levels, only the first embedded instance was considered when building the set of all methods. If the second instance was at a higher level, its methods would not be used. This only applied when building the set of all methods, so ambiguous cases were detected correctly. The bug only applied for non-ambiguous cases. I will commit a test case for this to the master testsuite.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.9 branch. Ian
diff -r 4e7f09e27159 go/types.cc --- a/go/types.cc Mon May 05 21:13:00 2014 -0400 +++ b/go/types.cc Tue May 06 01:15:54 2014 -0400 @@ -8924,9 +8924,8 @@ Methods** all_methods) { *all_methods = NULL; - Types_seen types_seen; - Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen, - all_methods); + std::vector<const Named_type*> seen; + Type::add_methods_for_type(type, NULL, 0, false, false, &seen, all_methods); Type::build_stub_methods(gogo, type, *all_methods, location); } @@ -8944,7 +8943,7 @@ unsigned int depth, bool is_embedded_pointer, bool needs_stub_method, - Types_seen* types_seen, + std::vector<const Named_type*>* seen, Methods** methods) { // Pointer types may not have methods. @@ -8954,19 +8953,24 @@ const Named_type* nt = type->named_type(); if (nt != NULL) { - std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt); - if (!ins.second) - return; - } - - if (nt != NULL) - Type::add_local_methods_for_type(nt, field_indexes, depth, - is_embedded_pointer, needs_stub_method, - methods); + for (std::vector<const Named_type*>::const_iterator p = seen->begin(); + p != seen->end(); + ++p) + { + if (*p == nt) + return; + } + + seen->push_back(nt); + + Type::add_local_methods_for_type(nt, field_indexes, depth, + is_embedded_pointer, needs_stub_method, + methods); + } Type::add_embedded_methods_for_type(type, field_indexes, depth, is_embedded_pointer, needs_stub_method, - types_seen, methods); + seen, methods); // If we are called with depth > 0, then we are looking at an // anonymous field of a struct. If such a field has interface type, @@ -8975,6 +8979,9 @@ // following the usual rules for an interface type. if (depth > 0) Type::add_interface_methods_for_type(type, field_indexes, depth, methods); + + if (nt != NULL) + seen->pop_back(); } // Add the local methods for the named type NT to *METHODS. The @@ -9020,7 +9027,7 @@ unsigned int depth, bool is_embedded_pointer, bool needs_stub_method, - Types_seen* types_seen, + std::vector<const Named_type*>* seen, Methods** methods) { // Look for anonymous fields in TYPE. TYPE has fields if it is a @@ -9064,7 +9071,7 @@ (needs_stub_method || is_pointer || i > 0), - types_seen, + seen, methods); } } diff -r 4e7f09e27159 go/types.h --- a/go/types.h Mon May 05 21:13:00 2014 -0400 +++ b/go/types.h Tue May 06 01:15:54 2014 -0400 @@ -1171,14 +1171,11 @@ static tree build_receive_return_type(tree type); - // A hash table we use to avoid infinite recursion. - typedef Unordered_set_hash(const Named_type*, Type_hash_identical, - Type_identical) Types_seen; - // Add all methods for TYPE to the list of methods for THIS. static void add_methods_for_type(const Type* type, const Method::Field_indexes*, - unsigned int depth, bool, bool, Types_seen*, + unsigned int depth, bool, bool, + std::vector<const Named_type*>*, Methods**); static void @@ -1189,7 +1186,8 @@ static void add_embedded_methods_for_type(const Type* type, const Method::Field_indexes*, - unsigned int depth, bool, bool, Types_seen*, + unsigned int depth, bool, bool, + std::vector<const Named_type*>*, Methods**); static void