compiler: Fix unnamed struct type converted to interface type.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 22 Sep 2012 01:15:28 +0000 (01:15 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 22 Sep 2012 01:15:28 +0000 (01:15 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@191627 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index 922b7df..08e830e 100644 (file)
@@ -293,19 +293,25 @@ Expression::convert_type_to_interface(Translate_context* context,
       // 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);
     }
index 4922c08..0d1746f 100644 (file)
@@ -2128,8 +2128,7 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
 
 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 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
   // 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 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
                                               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();
index 3d542ea..fa61808 100644 (file)
@@ -2872,7 +2872,8 @@ int
 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 @@ Build_method_tables::type(Type* type)
          // 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);
+               }
            }
        }
     }
index efd31f1..36709f5 100644 (file)
@@ -574,7 +574,7 @@ class Gogo
   // 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
index 6661920..3ae54a4 100644 (file)
@@ -4554,6 +4554,20 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
   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 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
        {
          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 @@ tree
 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 @@ Type::method_function(const Methods* methods, const std::string& name,
   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.
index 7b87924..cced68d 100644 (file)
@@ -983,6 +983,19 @@ class Type
   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 @@ class Struct_type : public Type
  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 @@ class Struct_type : public Type
   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 @@ class Struct_type : public Type
   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 @@ class Named_type : public Type
   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