compiler: Fix bug converting unnamed types with placeholders.
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 1 Dec 2012 00:15:16 +0000 (00:15 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 1 Dec 2012 00:15:16 +0000 (00:15 +0000)
From-SVN: r194011

gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index 7a4345d..c79181b 100644 (file)
@@ -45,8 +45,7 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
 // Class Type.
 
 Type::Type(Type_classification classification)
-  : classification_(classification), btype_is_placeholder_(false),
-    btype_(NULL), type_descriptor_var_(NULL)
+  : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
 {
 }
 
@@ -910,11 +909,7 @@ Btype*
 Type::get_backend(Gogo* gogo)
 {
   if (this->btype_ != NULL)
-    {
-      if (this->btype_is_placeholder_ && gogo->named_types_are_converted())
-       this->finish_backend(gogo);
-      return this->btype_;
-    }
+    return this->btype_;
 
   if (this->forward_declaration_type() != NULL
       || this->named_type() != NULL)
@@ -928,20 +923,36 @@ Type::get_backend(Gogo* gogo)
   // that.  There is no need to use the hash table for named types, as
   // named types are only identical to themselves.
 
-  std::pair<Type*, Btype*> val(this, NULL);
+  std::pair<Type*, Type_btype_entry> val;
+  val.first = this;
+  val.second.btype = NULL;
+  val.second.is_placeholder = false;
   std::pair<Type_btypes::iterator, bool> ins =
     Type::type_btypes.insert(val);
-  if (!ins.second && ins.first->second != NULL)
+  if (!ins.second && ins.first->second.btype != NULL)
     {
-      if (gogo != NULL && gogo->named_types_are_converted())
-       this->btype_ = ins.first->second;
-      return ins.first->second;
+      // Note that GOGO can be NULL here, but only when the GCC
+      // middle-end is asking for a frontend type.  That will only
+      // happen for simple types, which should never require
+      // placeholders.
+      if (!ins.first->second.is_placeholder)
+       this->btype_ = ins.first->second.btype;
+      else if (gogo->named_types_are_converted())
+       {
+         this->finish_backend(gogo, ins.first->second.btype);
+         ins.first->second.is_placeholder = false;
+       }
+
+      return ins.first->second.btype;
     }
 
   Btype* bt = this->get_btype_without_hash(gogo);
 
-  if (ins.first->second == NULL)
-    ins.first->second = bt;
+  if (ins.first->second.btype == NULL)
+    {
+      ins.first->second.btype = bt;
+      ins.first->second.is_placeholder = false;
+    }
   else
     {
       // We have already created a backend representation for this
@@ -949,10 +960,9 @@ Type::get_backend(Gogo* gogo)
       // a named type which in turns uses an identical unnamed type.
       // Use the tree we created earlier and ignore the one we just
       // built.
-      bt = ins.first->second;
-      if (gogo == NULL || !gogo->named_types_are_converted())
-       return bt;
-      this->btype_ = bt;
+      if (this->btype_ == bt)
+       this->btype_ = ins.first->second.btype;
+      bt = ins.first->second.btype;
     }
 
   return bt;
@@ -1019,6 +1029,37 @@ Type::get_backend_placeholder(Gogo* gogo)
       // These are simple types that can just be created directly.
       return this->get_backend(gogo);
 
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      // All maps and channels have the same backend representation.
+      return this->get_backend(gogo);
+
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
+      // Named types keep track of their own dependencies and manage
+      // their own placeholders.
+      return this->get_backend(gogo);
+
+    case TYPE_INTERFACE:
+      if (this->interface_type()->is_empty())
+       return Interface_type::get_backend_empty_interface_type(gogo);
+      break;
+
+    default:
+      break;
+    }
+
+  std::pair<Type*, Type_btype_entry> val;
+  val.first = this;
+  val.second.btype = NULL;
+  val.second.is_placeholder = false;
+  std::pair<Type_btypes::iterator, bool> ins =
+    Type::type_btypes.insert(val);
+  if (!ins.second && ins.first->second.btype != NULL)
+    return ins.first->second.btype;
+
+  switch (this->classification_)
+    {
     case TYPE_FUNCTION:
       {
        Location loc = this->function_type()->location();
@@ -1061,37 +1102,36 @@ Type::get_backend_placeholder(Gogo* gogo)
        }
       break;
        
-    case TYPE_MAP:
-    case TYPE_CHANNEL:
-      // All maps and channels have the same backend representation.
-      return this->get_backend(gogo);
-
     case TYPE_INTERFACE:
-      if (this->interface_type()->is_empty())
-       return Interface_type::get_backend_empty_interface_type(gogo);
-      else
-       {
-         std::vector<Backend::Btyped_identifier> bfields;
-         get_backend_interface_fields(gogo, this->interface_type(), true,
-                                      &bfields);
-         bt = gogo->backend()->struct_type(bfields);
-       }
+      {
+       go_assert(!this->interface_type()->is_empty());
+       std::vector<Backend::Btyped_identifier> bfields;
+       get_backend_interface_fields(gogo, this->interface_type(), true,
+                                    &bfields);
+       bt = gogo->backend()->struct_type(bfields);
+      }
       break;
 
-    case TYPE_NAMED:
-    case TYPE_FORWARD:
-      // Named types keep track of their own dependencies and manage
-      // their own placeholders.
-      return this->get_backend(gogo);
-
     case TYPE_SINK:
     case TYPE_CALL_MULTIPLE_RESULT:
+      /* Note that various classifications were handled in the earlier
+        switch.  */
     default:
       go_unreachable();
     }
 
-  this->btype_ = bt;
-  this->btype_is_placeholder_ = true;
+  if (ins.first->second.btype == NULL)
+    {
+      ins.first->second.btype = bt;
+      ins.first->second.is_placeholder = true;
+    }
+  else
+    {
+      // A placeholder for this type got created along the way.  Use
+      // that one and ignore the one we just built.
+      bt = ins.first->second.btype;
+    }
+
   return bt;
 }
 
@@ -1099,12 +1139,8 @@ Type::get_backend_placeholder(Gogo* gogo)
 // using a placeholder type.
 
 void
-Type::finish_backend(Gogo* gogo)
+Type::finish_backend(Gogo* gogo, Btype *placeholder)
 {
-  go_assert(this->btype_ != NULL);
-  if (!this->btype_is_placeholder_)
-    return;
-
   switch (this->classification_)
     {
     case TYPE_ERROR:
@@ -1120,7 +1156,7 @@ Type::finish_backend(Gogo* gogo)
     case TYPE_FUNCTION:
       {
        Btype* bt = this->do_get_backend(gogo);
-       if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt))
+       if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
          go_assert(saw_errors());
       }
       break;
@@ -1128,7 +1164,7 @@ Type::finish_backend(Gogo* gogo)
     case TYPE_POINTER:
       {
        Btype* bt = this->do_get_backend(gogo);
-       if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt))
+       if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
          go_assert(saw_errors());
       }
       break;
@@ -1165,7 +1201,7 @@ Type::finish_backend(Gogo* gogo)
       go_unreachable();
     }
 
-  this->btype_is_placeholder_ = false;
+  this->btype_ = placeholder;
 }
 
 // Return a pointer to the type descriptor for this type.
@@ -2968,8 +3004,8 @@ String_type::do_get_backend(Gogo* gogo)
       // backend representation, so force it to be finished now.
       if (!gogo->named_types_are_converted())
        {
-         pb->get_backend_placeholder(gogo);
-         pb->finish_backend(gogo);
+         Btype* bt = pb->get_backend_placeholder(gogo);
+         pb->finish_backend(gogo, bt);
        }
 
       fields[0].name = "__data";
index 2ab21f6..fc84db0 100644 (file)
@@ -888,7 +888,7 @@ class Type
 
   // Finish the backend representation of a placeholder.
   void
-  finish_backend(Gogo*);
+  finish_backend(Gogo*, Btype*);
 
   // Build a type descriptor entry for this type.  Return a pointer to
   // it.  The location is the location which causes us to need the
@@ -1210,10 +1210,18 @@ class Type
   Btype*
   get_btype_without_hash(Gogo*);
 
+  // A backend type that may be a placeholder.
+  struct Type_btype_entry
+  {
+    Btype *btype;
+    bool is_placeholder;
+  };
+
   // A mapping from Type to Btype*, used to ensure that the backend
-  // representation of identical types is identical.
-  typedef Unordered_map_hash(const Type*, Btype*, Type_hash_identical,
-                            Type_identical) Type_btypes;
+  // representation of identical types is identical.  This is only
+  // used for unnamed types.
+  typedef Unordered_map_hash(const Type*, Type_btype_entry,
+                            Type_hash_identical, Type_identical) Type_btypes;
 
   static Type_btypes type_btypes;
 
@@ -1230,9 +1238,6 @@ class Type
 
   // The type classification.
   Type_classification classification_;
-  // Whether btype_ is a placeholder type used while named types are
-  // being converted.
-  bool btype_is_placeholder_;
   // The backend representation of the type, once it has been
   // determined.
   Btype* btype_;