Patchwork Go patch committed: Fix unnamed struct converted to interface

login
register
mail settings
Submitter Ian Taylor
Date Sept. 22, 2012, 1:16 a.m.
Message ID <mcrvcf6oo07.fsf@google.com>
Download mbox | patch
Permalink /patch/186008/
State New
Headers show

Comments

Ian Taylor - Sept. 22, 2012, 1:16 a.m.
This patch to the Go frontend fixes the handling of an unnamed struct
type with methods (inherited from embedded fields) converted to an
interface type.  Previously the interface method table was being stored
as NULL, causing a runtime crash.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline and 4.7 branch.

Ian

Patch

diff -r 561942122df7 go/expressions.cc
--- a/go/expressions.cc	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/expressions.cc	Fri Sep 21 18:10:51 2012 -0700
@@ -293,19 +293,25 @@ 
       // object type: a list of function pointers for each interface
       // method.
       Named_type* rhs_named_type = rhs_type->named_type();
+      Struct_type* rhs_struct_type = rhs_type->struct_type();
       bool is_pointer = false;
-      if (rhs_named_type == NULL)
+      if (rhs_named_type == NULL && rhs_struct_type == NULL)
 	{
 	  rhs_named_type = rhs_type->deref()->named_type();
+	  rhs_struct_type = rhs_type->deref()->struct_type();
 	  is_pointer = true;
 	}
       tree method_table;
-      if (rhs_named_type == NULL)
-	method_table = null_pointer_node;
-      else
+      if (rhs_named_type != NULL)
 	method_table =
 	  rhs_named_type->interface_method_table(gogo, lhs_interface_type,
 						 is_pointer);
+      else if (rhs_struct_type != NULL)
+	method_table =
+	  rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
+						  is_pointer);
+      else
+	method_table = null_pointer_node;
       first_field_value = fold_convert_loc(location.gcc_location(),
                                            const_ptr_type_node, method_table);
     }
diff -r 561942122df7 go/gogo-tree.cc
--- a/go/gogo-tree.cc	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/gogo-tree.cc	Fri Sep 21 18:10:51 2012 -0700
@@ -2128,8 +2128,7 @@ 
 
 tree
 Gogo::interface_method_table_for_type(const Interface_type* interface,
-				      Named_type* type,
-				      bool is_pointer)
+				      Type* type, bool is_pointer)
 {
   const Typed_identifier_list* interface_methods = interface->methods();
   go_assert(!interface_methods->empty());
@@ -2158,7 +2157,9 @@ 
   // interface.  If the interface has hidden methods, and the named
   // type is defined in a different package, then the interface
   // conversion table will be defined by that other package.
-  if (has_hidden_methods && type->named_object()->package() != NULL)
+  if (has_hidden_methods
+      && type->named_type() != NULL
+      && type->named_type()->named_object()->package() != NULL)
     {
       tree array_type = build_array_type(const_ptr_type_node, NULL);
       tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
@@ -2187,13 +2188,20 @@ 
                                               Linemap::predeclared_location());
   elt->value = fold_convert(const_ptr_type_node, tdp);
 
+  Named_type* nt = type->named_type();
+  Struct_type* st = type->struct_type();
+  go_assert(nt != NULL || st != NULL);
   size_t i = 1;
   for (Typed_identifier_list::const_iterator p = interface_methods->begin();
        p != interface_methods->end();
        ++p, ++i)
     {
       bool is_ambiguous;
-      Method* m = type->method_function(p->name(), &is_ambiguous);
+      Method* m;
+      if (nt != NULL)
+	m = nt->method_function(p->name(), &is_ambiguous);
+      else
+	m = st->method_function(p->name(), &is_ambiguous);
       go_assert(m != NULL);
 
       Named_object* no = m->named_object();
diff -r 561942122df7 go/gogo.cc
--- a/go/gogo.cc	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/gogo.cc	Fri Sep 21 18:10:51 2012 -0700
@@ -2872,7 +2872,8 @@ 
 Build_method_tables::type(Type* type)
 {
   Named_type* nt = type->named_type();
-  if (nt != NULL)
+  Struct_type* st = type->struct_type();
+  if (nt != NULL || st != NULL)
     {
       for (std::vector<Interface_type*>::const_iterator p =
 	     this->interfaces_.begin();
@@ -2882,10 +2883,23 @@ 
 	  // We ask whether a pointer to the named type implements the
 	  // interface, because a pointer can implement more methods
 	  // than a value.
-	  if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL))
+	  if (nt != NULL)
 	    {
-	      nt->interface_method_table(this->gogo_, *p, false);
-	      nt->interface_method_table(this->gogo_, *p, true);
+	      if ((*p)->implements_interface(Type::make_pointer_type(nt),
+					     NULL))
+		{
+		  nt->interface_method_table(this->gogo_, *p, false);
+		  nt->interface_method_table(this->gogo_, *p, true);
+		}
+	    }
+	  else
+	    {
+	      if ((*p)->implements_interface(Type::make_pointer_type(st),
+					     NULL))
+		{
+		  st->interface_method_table(this->gogo_, *p, false);
+		  st->interface_method_table(this->gogo_, *p, true);
+		}
 	    }
 	}
     }
diff -r 561942122df7 go/gogo.h
--- a/go/gogo.h	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/gogo.h	Fri Sep 21 18:10:51 2012 -0700
@@ -574,7 +574,7 @@ 
   // Build an interface method table for a type: a list of function
   // pointers, one for each interface method.  This returns a decl.
   tree
-  interface_method_table_for_type(const Interface_type*, Named_type*,
+  interface_method_table_for_type(const Interface_type*, Type*,
 				  bool is_pointer);
 
   // Return a tree which allocate SIZE bytes to hold values of type
diff -r 561942122df7 go/types.cc
--- a/go/types.cc	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/types.cc	Fri Sep 21 18:10:51 2012 -0700
@@ -4554,6 +4554,20 @@ 
   return Type::method_function(this->all_methods_, name, is_ambiguous);
 }
 
+// Return a pointer to the interface method table for this type for
+// the interface INTERFACE.  IS_POINTER is true if this is for a
+// pointer to THIS.
+
+tree
+Struct_type::interface_method_table(Gogo* gogo,
+				    const Interface_type* interface,
+				    bool is_pointer)
+{
+  return Type::interface_method_table(gogo, this, interface, is_pointer,
+				      &this->interface_method_tables_,
+				      &this->pointer_interface_method_tables_);
+}
+
 // Convert struct fields to the backend representation.  This is not
 // declared in types.h so that types.h doesn't have to #include
 // backend.h.
@@ -7182,7 +7196,17 @@ 
 	{
 	  if (!p->name().empty())
 	    {
-	      std::string n = Gogo::unpack_hidden_name(p->name());
+	      std::string n;
+	      if (!Gogo::is_hidden_name(p->name()))
+		n = p->name();
+	      else
+		{
+		  n = ".";
+		  std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
+		  n.append(Gogo::pkgpath_for_symbol(pkgpath));
+		  n.append(1, '.');
+		  n.append(Gogo::unpack_hidden_name(p->name()));
+		}
 	      char buf[20];
 	      snprintf(buf, sizeof buf, "%u_",
 		       static_cast<unsigned int>(n.length()));
@@ -7735,32 +7759,9 @@ 
 Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
 				   bool is_pointer)
 {
-  go_assert(!interface->is_empty());
-
-  Interface_method_tables** pimt = (is_pointer
-				    ? &this->interface_method_tables_
-				    : &this->pointer_interface_method_tables_);
-
-  if (*pimt == NULL)
-    *pimt = new Interface_method_tables(5);
-
-  std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
-  std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
-
-  if (ins.second)
-    {
-      // This is a new entry in the hash table.
-      go_assert(ins.first->second == NULL_TREE);
-      ins.first->second = gogo->interface_method_table_for_type(interface,
-								this,
-								is_pointer);
-    }
-
-  tree decl = ins.first->second;
-  if (decl == error_mark_node)
-    return error_mark_node;
-  go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
-  return build_fold_addr_expr(decl);
+  return Type::interface_method_table(gogo, this, interface, is_pointer,
+				      &this->interface_method_tables_,
+				      &this->pointer_interface_method_tables_);
 }
 
 // Return whether a named type has any hidden fields.
@@ -8944,6 +8945,42 @@ 
   return m;
 }
 
+// Return a pointer to the interface method table for TYPE for the
+// interface INTERFACE.
+
+tree
+Type::interface_method_table(Gogo* gogo, Type* type,
+			     const Interface_type *interface,
+			     bool is_pointer,
+			     Interface_method_tables** method_tables,
+			     Interface_method_tables** pointer_tables)
+{
+  go_assert(!interface->is_empty());
+
+  Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables;
+
+  if (*pimt == NULL)
+    *pimt = new Interface_method_tables(5);
+
+  std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
+  std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
+
+  if (ins.second)
+    {
+      // This is a new entry in the hash table.
+      go_assert(ins.first->second == NULL_TREE);
+      ins.first->second = gogo->interface_method_table_for_type(interface,
+								type,
+								is_pointer);
+    }
+
+  tree decl = ins.first->second;
+  if (decl == error_mark_node)
+    return error_mark_node;
+  go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
+  return build_fold_addr_expr(decl);
+}
+
 // Look for field or method NAME for TYPE.  Return an Expression for
 // the field or method bound to EXPR.  If there is no such field or
 // method, give an appropriate error and return an error expression.
diff -r 561942122df7 go/types.h
--- a/go/types.h	Fri Sep 21 15:10:32 2012 -0700
+++ b/go/types.h	Fri Sep 21 18:10:51 2012 -0700
@@ -983,6 +983,19 @@ 
   method_function(const Methods*, const std::string& name,
 		  bool* is_ambiguous);
 
+  // A mapping from interfaces to the associated interface method
+  // tables for this type.  This maps to a decl.
+  typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
+			     Type_identical) Interface_method_tables;
+
+  // Return a pointer to the interface method table for TYPE for the
+  // interface INTERFACE.
+  static tree
+  interface_method_table(Gogo* gogo, Type* type,
+			 const Interface_type *interface, bool is_pointer,
+			 Interface_method_tables** method_tables,
+			 Interface_method_tables** pointer_tables);
+
   // Return a composite literal for the type descriptor entry for a
   // type.
   static Expression*
@@ -1994,7 +2007,8 @@ 
  public:
   Struct_type(Struct_field_list* fields, Location location)
     : Type(TYPE_STRUCT),
-      fields_(fields), location_(location), all_methods_(NULL)
+      fields_(fields), location_(location), all_methods_(NULL),
+      interface_method_tables_(NULL), pointer_interface_method_tables_(NULL)
   { }
 
   // Return the field NAME.  This only looks at local fields, not at
@@ -2076,6 +2090,14 @@ 
   Method*
   method_function(const std::string& name, bool* is_ambiguous) const;
 
+  // Return a pointer to the interface method table for this type for
+  // the interface INTERFACE.  If IS_POINTER is true, set the type
+  // descriptor to a pointer to this type, otherwise set it to this
+  // type.
+  tree
+  interface_method_table(Gogo*, const Interface_type* interface,
+			 bool is_pointer);
+
   // Traverse just the field types of a struct type.
   int
   traverse_field_types(Traverse* traverse)
@@ -2156,6 +2178,13 @@ 
   Location location_;
   // If this struct is unnamed, a list of methods.
   Methods* all_methods_;
+  // A mapping from interfaces to the associated interface method
+  // tables for this type.  Only used if this struct is unnamed.
+  Interface_method_tables* interface_method_tables_;
+  // A mapping from interfaces to the associated interface method
+  // tables for pointers to this type.  Only used if this struct is
+  // unnamed.
+  Interface_method_tables* pointer_interface_method_tables_;
 };
 
 // The type of an array.
@@ -2861,11 +2890,6 @@ 
   void
   create_placeholder(Gogo*);
 
-  // A mapping from interfaces to the associated interface method
-  // tables for this type.  This maps to a decl.
-  typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
-			     Type_identical) Interface_method_tables;
-
   // A pointer back to the Named_object for this type.
   Named_object* named_object_;
   // If this type is defined in a function, a pointer back to the