This patch from Tim Shen fixes a bug in the Go frontend in which a promoted method could be used even if there was a field of the same name. This fixes http://golang.org/issue/4365 . Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r c9d064a071c9 go/types.cc --- a/go/types.cc Fri Oct 03 08:11:52 2014 -0700 +++ b/go/types.cc Fri Oct 03 08:12:08 2014 -0700 @@ -9387,9 +9387,14 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location, Methods** all_methods) { - *all_methods = NULL; + *all_methods = new Methods(); std::vector<const Named_type*> seen; - Type::add_methods_for_type(type, NULL, 0, false, false, &seen, all_methods); + Type::add_methods_for_type(type, NULL, 0, false, false, &seen, *all_methods); + if ((*all_methods)->empty()) + { + delete *all_methods; + *all_methods = NULL; + } Type::build_stub_methods(gogo, type, *all_methods, location); } @@ -9408,7 +9413,7 @@ bool is_embedded_pointer, bool needs_stub_method, std::vector<const Named_type*>* seen, - Methods** methods) + Methods* methods) { // Pointer types may not have methods. if (type->points_to() != NULL) @@ -9457,15 +9462,12 @@ unsigned int depth, bool is_embedded_pointer, bool needs_stub_method, - Methods** methods) + Methods* methods) { const Bindings* local_methods = nt->local_methods(); if (local_methods == NULL) return; - if (*methods == NULL) - *methods = new Methods(); - for (Bindings::const_declarations_iterator p = local_methods->begin_declarations(); p != local_methods->end_declarations(); @@ -9476,7 +9478,7 @@ || !Type::method_expects_pointer(no)); Method* m = new Named_method(no, field_indexes, depth, is_value_method, (needs_stub_method || depth > 0)); - if (!(*methods)->insert(no->name(), m)) + if (!methods->insert(no->name(), m)) delete m; } } @@ -9492,7 +9494,7 @@ bool is_embedded_pointer, bool needs_stub_method, std::vector<const Named_type*>* seen, - Methods** methods) + Methods* methods) { // Look for anonymous fields in TYPE. TYPE has fields if it is a // struct. @@ -9530,13 +9532,35 @@ sub_field_indexes->next = field_indexes; sub_field_indexes->field_index = i; + Methods tmp_methods; Type::add_methods_for_type(fnt, sub_field_indexes, depth + 1, (is_embedded_pointer || is_pointer), (needs_stub_method || is_pointer || i > 0), seen, - methods); + &tmp_methods); + // Check if there are promoted methods that conflict with field names and + // don't add them to the method map. + for (Methods::const_iterator p = tmp_methods.begin(); + p != tmp_methods.end(); + ++p) + { + bool found = false; + for (Struct_field_list::const_iterator fp = fields->begin(); + fp != fields->end(); + ++fp) + { + if (fp->field_name() == p->first) + { + found = true; + break; + } + } + if (!found && + !methods->insert(p->first, p->second)) + delete p->second; + } } } @@ -9548,7 +9572,7 @@ Type::add_interface_methods_for_type(const Type* type, const Method::Field_indexes* field_indexes, unsigned int depth, - Methods** methods) + Methods* methods) { const Interface_type* it = type->interface_type(); if (it == NULL) @@ -9558,9 +9582,6 @@ if (imethods == NULL) return; - if (*methods == NULL) - *methods = new Methods(); - for (Typed_identifier_list::const_iterator pm = imethods->begin(); pm != imethods->end(); ++pm) @@ -9576,7 +9597,7 @@ fntype = fntype->copy_with_receiver(const_cast<Type*>(type)); Method* m = new Interface_method(pm->name(), pm->location(), fntype, field_indexes, depth); - if (!(*methods)->insert(pm->name(), m)) + if (!methods->insert(pm->name(), m)) delete m; } } diff -r c9d064a071c9 go/types.h --- a/go/types.h Fri Oct 03 08:11:52 2014 -0700 +++ b/go/types.h Fri Oct 03 08:12:08 2014 -0700 @@ -384,6 +384,10 @@ find(const std::string& name) const { return this->methods_.find(name); } + bool + empty() const + { return this->methods_.empty(); } + private: Method_map methods_; }; @@ -1228,24 +1232,24 @@ add_methods_for_type(const Type* type, const Method::Field_indexes*, unsigned int depth, bool, bool, std::vector<const Named_type*>*, - Methods**); + Methods*); static void add_local_methods_for_type(const Named_type* type, const Method::Field_indexes*, - unsigned int depth, bool, bool, Methods**); + unsigned int depth, bool, bool, Methods*); static void add_embedded_methods_for_type(const Type* type, const Method::Field_indexes*, unsigned int depth, bool, bool, std::vector<const Named_type*>*, - Methods**); + Methods*); static void add_interface_methods_for_type(const Type* type, const Method::Field_indexes*, - unsigned int depth, Methods**); + unsigned int depth, Methods*); // Build stub methods for a type. static void