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

Reply via email to