OSDN Git Service

compiler: Fix crash: type T1 struct { F *[1]T2 } where T2 is a struct.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / types.cc
index 1a35e54..13cd48a 100644 (file)
@@ -34,10 +34,28 @@ extern "C"
 #include "backend.h"
 #include "types.h"
 
+// Forward declarations so that we don't have to make types.h #include
+// backend.h.
+
+static void
+get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
+                         bool use_placeholder,
+                         std::vector<Backend::Btyped_identifier>* bfields);
+
+static void
+get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
+                        std::vector<Backend::Btyped_identifier>* bfields);
+
+static void
+get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+                            bool use_placeholder,
+                            std::vector<Backend::Btyped_identifier>* bfields);
+
 // Class Type.
 
 Type::Type(Type_classification classification)
-  : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
+  : classification_(classification), btype_is_placeholder_(false),
+    btype_(NULL), type_descriptor_var_(NULL)
 {
 }
 
@@ -895,7 +913,11 @@ Btype*
 Type::get_backend(Gogo* gogo)
 {
   if (this->btype_ != NULL)
-    return this->btype_;
+    {
+      if (this->btype_is_placeholder_ && gogo->named_types_are_converted())
+       this->finish_backend(gogo);
+      return this->btype_;
+    }
 
   if (this->forward_declaration_type() != NULL
       || this->named_type() != NULL)
@@ -966,6 +988,189 @@ Type::get_btype_without_hash(Gogo* gogo)
   return this->btype_;
 }
 
+// Get the backend representation of a type without forcing the
+// creation of the backend representation of all supporting types.
+// This will return a backend type that has the correct size but may
+// be incomplete.  E.g., a pointer will just be a placeholder pointer,
+// and will not contain the final representation of the type to which
+// it points.  This is used while converting all named types to the
+// backend representation, to avoid problems with indirect references
+// to types which are not yet complete.  When this is called, the
+// sizes of all direct references (e.g., a struct field) should be
+// known, but the sizes of indirect references (e.g., the type to
+// which a pointer points) may not.
+
+Btype*
+Type::get_backend_placeholder(Gogo* gogo)
+{
+  if (gogo->named_types_are_converted())
+    return this->get_backend(gogo);
+  if (this->btype_ != NULL)
+    return this->btype_;
+
+  Btype* bt;
+  switch (this->classification_)
+    {
+    case TYPE_ERROR:
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      // These are simple types that can just be created directly.
+      return this->get_backend(gogo);
+
+    case TYPE_FUNCTION:
+      {
+       Location loc = this->function_type()->location();
+       bt = gogo->backend()->placeholder_pointer_type("", loc, true);
+      }
+      break;
+
+    case TYPE_POINTER:
+      {
+       Location loc = Linemap::unknown_location();
+       bt = gogo->backend()->placeholder_pointer_type("", loc, false);
+      }
+      break;
+
+    case TYPE_STRUCT:
+      // We don't have to make the struct itself be a placeholder.  We
+      // are promised that we know the sizes of the struct fields.
+      // But we may have to use a placeholder for any particular
+      // struct field.
+      {
+       std::vector<Backend::Btyped_identifier> bfields;
+       get_backend_struct_fields(gogo, this->struct_type()->fields(),
+                                 true, &bfields);
+       bt = gogo->backend()->struct_type(bfields);
+      }
+      break;
+
+    case TYPE_ARRAY:
+      if (this->is_slice_type())
+       {
+         std::vector<Backend::Btyped_identifier> bfields;
+         get_backend_slice_fields(gogo, this->array_type(), true, &bfields);
+         bt = gogo->backend()->struct_type(bfields);
+       }
+      else
+       {
+         Btype* element = this->array_type()->get_backend_element(gogo, true);
+         Bexpression* len = this->array_type()->get_backend_length(gogo);
+         bt = gogo->backend()->array_type(element, len);
+       }
+      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);
+       }
+      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:
+    default:
+      go_unreachable();
+    }
+
+  this->btype_ = bt;
+  this->btype_is_placeholder_ = true;
+  return bt;
+}
+
+// Complete the backend representation.  This is called for a type
+// using a placeholder type.
+
+void
+Type::finish_backend(Gogo* gogo)
+{
+  go_assert(this->btype_ != NULL);
+  if (!this->btype_is_placeholder_)
+    return;
+
+  switch (this->classification_)
+    {
+    case TYPE_ERROR:
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      go_unreachable();
+
+    case TYPE_FUNCTION:
+      {
+       Btype* bt = this->do_get_backend(gogo);
+       if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt))
+         go_assert(saw_errors());
+      }
+      break;
+
+    case TYPE_POINTER:
+      {
+       Btype* bt = this->do_get_backend(gogo);
+       if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt))
+         go_assert(saw_errors());
+      }
+      break;
+
+    case TYPE_STRUCT:
+      // The struct type itself is done, but we have to make sure that
+      // all the field types are converted.
+      this->struct_type()->finish_backend_fields(gogo);
+      break;
+
+    case TYPE_ARRAY:
+      // The array type itself is done, but make sure the element type
+      // is converted.
+      this->array_type()->finish_backend_element(gogo);
+      break;
+       
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      go_unreachable();
+
+    case TYPE_INTERFACE:
+      // The interface type itself is done, but make sure the method
+      // types are converted.
+      this->interface_type()->finish_backend_methods(gogo);
+      break;
+
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
+      go_unreachable();
+
+    case TYPE_SINK:
+    case TYPE_CALL_MULTIPLE_RESULT:
+    default:
+      go_unreachable();
+    }
+
+  this->btype_is_placeholder_ = false;
+}
+
 // Return a pointer to the type descriptor for this type.
 
 tree
@@ -2059,7 +2264,8 @@ Type::backend_type_size(Gogo* gogo, unsigned int *psize)
 {
   if (!this->is_backend_type_size_known(gogo))
     return false;
-  size_t size = gogo->backend()->type_size(this->get_backend(gogo));
+  Btype* bt = this->get_backend_placeholder(gogo);
+  size_t size = gogo->backend()->type_size(bt);
   *psize = static_cast<unsigned int>(size);
   if (*psize != size)
     return false;
@@ -2074,7 +2280,8 @@ Type::backend_type_align(Gogo* gogo, unsigned int *palign)
 {
   if (!this->is_backend_type_size_known(gogo))
     return false;
-  size_t align = gogo->backend()->type_alignment(this->get_backend(gogo));
+  Btype* bt = this->get_backend_placeholder(gogo);
+  size_t align = gogo->backend()->type_alignment(bt);
   *palign = static_cast<unsigned int>(align);
   if (*palign != align)
     return false;
@@ -2089,7 +2296,8 @@ Type::backend_type_field_align(Gogo* gogo, unsigned int *palign)
 {
   if (!this->is_backend_type_size_known(gogo))
     return false;
-  size_t a = gogo->backend()->type_field_alignment(this->get_backend(gogo));
+  Btype* bt = this->get_backend_placeholder(gogo);
+  size_t a = gogo->backend()->type_field_alignment(bt);
   *palign = static_cast<unsigned int>(a);
   if (*palign != a)
     return false;
@@ -2712,6 +2920,15 @@ String_type::do_get_backend(Gogo* gogo)
 
       Type* b = gogo->lookup_global("byte")->type_value();
       Type* pb = Type::make_pointer_type(b);
+
+      // We aren't going to get back to this field to finish the
+      // backend representation, so force it to be finished now.
+      if (!gogo->named_types_are_converted())
+       {
+         pb->get_backend_placeholder(gogo);
+         pb->finish_backend(gogo);
+       }
+
       fields[0].name = "__data";
       fields[0].btype = pb->get_backend(gogo);
       fields[0].location = Linemap::predeclared_location();
@@ -3117,7 +3334,7 @@ Function_type::do_hash_for_method(Gogo* gogo) const
 // Get the backend representation for a function type.
 
 Btype*
-Function_type::get_function_backend(Gogo* gogo)
+Function_type::do_get_backend(Gogo* gogo)
 {
   Backend::Btyped_identifier breceiver;
   if (this->receiver_ != NULL)
@@ -3169,46 +3386,6 @@ Function_type::get_function_backend(Gogo* gogo)
                                        this->location());
 }
 
-// A hash table mapping function types to their backend placeholders.
-
-Function_type::Placeholders Function_type::placeholders;
-
-// Get the backend representation for a function type.  If we are
-// still converting types, and this types has multiple results, return
-// a placeholder instead.  We do this because for multiple results we
-// build a struct, and we need to make sure that all the types in the
-// struct are valid before we create the struct.
-
-Btype*
-Function_type::do_get_backend(Gogo* gogo)
-{
-  if (!gogo->named_types_are_converted()
-      && this->results_ != NULL
-      && this->results_->size() > 1)
-    {
-      Btype* placeholder =
-       gogo->backend()->placeholder_pointer_type("", this->location(), true);
-      Function_type::placeholders.push_back(std::make_pair(this, placeholder));
-      return placeholder;
-    }
-  return this->get_function_backend(gogo);
-}
-
-// Convert function types after all named types are converted.
-
-void
-Function_type::convert_types(Gogo* gogo)
-{
-  for (Placeholders::const_iterator p = Function_type::placeholders.begin();
-       p != Function_type::placeholders.end();
-       ++p)
-    {
-      Btype* bt = p->first->get_function_backend(gogo);
-      if (!gogo->backend()->set_placeholder_function_type(p->second, bt))
-       go_assert(saw_errors());
-    }
-}
-
 // The type of a function type descriptor.
 
 Type*
@@ -4346,6 +4523,7 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
 
 static void
 get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
+                         bool use_placeholder,
                          std::vector<Backend::Btyped_identifier>* bfields)
 {
   bfields->resize(fields->size());
@@ -4355,7 +4533,9 @@ get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
        ++p, ++i)
     {
       (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name());
-      (*bfields)[i].btype = p->type()->get_backend(gogo);
+      (*bfields)[i].btype = (use_placeholder
+                            ? p->type()->get_backend_placeholder(gogo)
+                            : p->type()->get_backend(gogo));
       (*bfields)[i].location = p->location();
     }
   go_assert(i == fields->size());
@@ -4367,10 +4547,25 @@ Btype*
 Struct_type::do_get_backend(Gogo* gogo)
 {
   std::vector<Backend::Btyped_identifier> bfields;
-  get_backend_struct_fields(gogo, this->fields_, &bfields);
+  get_backend_struct_fields(gogo, this->fields_, false, &bfields);
   return gogo->backend()->struct_type(bfields);
 }
 
+// Finish the backend representation of the fields of a struct.
+
+void
+Struct_type::finish_backend_fields(Gogo* gogo)
+{
+  const Struct_field_list* fields = this->fields_;
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator p = fields->begin();
+          p != fields->end();
+          ++p)
+       p->type()->get_backend(gogo);
+    }
+}
+
 // The type of a struct type descriptor.
 
 Type*
@@ -4776,8 +4971,8 @@ Struct_type::backend_field_offset(Gogo* gogo, unsigned int index,
 {
   if (!this->is_backend_type_size_known(gogo))
     return false;
-  size_t offset = gogo->backend()->type_field_offset(this->get_backend(gogo),
-                                                    index);
+  Btype* bt = this->get_backend_placeholder(gogo);
+  size_t offset = gogo->backend()->type_field_offset(bt, index);
   *poffset = static_cast<unsigned int>(offset);
   if (*poffset != offset)
     return false;
@@ -5295,13 +5490,15 @@ Array_type::get_length_tree(Gogo* gogo)
 // size which does not fit in int.
 
 static void
-get_backend_slice_fields(Gogo* gogo, Array_type* type,
+get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
                         std::vector<Backend::Btyped_identifier>* bfields)
 {
   bfields->resize(3);
 
   Type* pet = Type::make_pointer_type(type->element_type());
-  Btype* pbet = pet->get_backend(gogo);
+  Btype* pbet = (use_placeholder
+                ? pet->get_backend_placeholder(gogo)
+                : pet->get_backend(gogo));
   Location ploc = Linemap::predeclared_location();
 
   Backend::Btyped_identifier* p = &(*bfields)[0];
@@ -5333,12 +5530,12 @@ Array_type::do_get_backend(Gogo* gogo)
   if (this->length_ == NULL)
     {
       std::vector<Backend::Btyped_identifier> bfields;
-      get_backend_slice_fields(gogo, this, &bfields);
+      get_backend_slice_fields(gogo, this, false, &bfields);
       return gogo->backend()->struct_type(bfields);
     }
   else
     {
-      Btype* element = this->get_backend_element(gogo);
+      Btype* element = this->get_backend_element(gogo, false);
       Bexpression* len = this->get_backend_length(gogo);
       return gogo->backend()->array_type(element, len);
     }
@@ -5347,9 +5544,12 @@ Array_type::do_get_backend(Gogo* gogo)
 // Return the backend representation of the element type.
 
 Btype*
-Array_type::get_backend_element(Gogo* gogo)
+Array_type::get_backend_element(Gogo* gogo, bool use_placeholder)
 {
-  return this->element_type_->get_backend(gogo);
+  if (use_placeholder)
+    return this->element_type_->get_backend_placeholder(gogo);
+  else
+    return this->element_type_->get_backend(gogo);
 }
 
 // Return the backend representation of the length.
@@ -5360,6 +5560,22 @@ Array_type::get_backend_length(Gogo* gogo)
   return tree_to_expr(this->get_length_tree(gogo));
 }
 
+// Finish backend representation of the array.
+
+void
+Array_type::finish_backend_element(Gogo* gogo)
+{
+  Type* et = this->array_type()->element_type();
+  et->get_backend(gogo);
+  if (this->is_slice_type())
+    {
+      // This relies on the fact that we always use the same
+      // structure for a pointer to any given type.
+      Type* pet = Type::make_pointer_type(et);
+      pet->get_backend(gogo);
+    }
+}
+
 // Return a tree for a pointer to the values in ARRAY.
 
 tree
@@ -6652,6 +6868,7 @@ Interface_type::get_backend_empty_interface_type(Gogo* gogo)
 
 static void
 get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+                            bool use_placeholder,
                             std::vector<Backend::Btyped_identifier>* bfields)
 {
   Location loc = type->location();
@@ -6670,7 +6887,9 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
        ++p, ++i)
     {
       mfields[i].name = Gogo::unpack_hidden_name(p->name());
-      mfields[i].btype = p->type()->get_backend(gogo);
+      mfields[i].btype = (use_placeholder
+                         ? p->type()->get_backend_placeholder(gogo)
+                         : p->type()->get_backend(gogo));
       mfields[i].location = loc;
       // Sanity check: the names should be sorted.
       go_assert(p->name() > last_name);
@@ -6710,7 +6929,7 @@ Interface_type::do_get_backend(Gogo* gogo)
       this->interface_btype_ =
        gogo->backend()->placeholder_struct_type("", this->location_);
       std::vector<Backend::Btyped_identifier> bfields;
-      get_backend_interface_fields(gogo, this, &bfields);
+      get_backend_interface_fields(gogo, this, false, &bfields);
       if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_,
                                                        bfields))
        this->interface_btype_ = gogo->backend()->error_type();
@@ -6718,6 +6937,24 @@ Interface_type::do_get_backend(Gogo* gogo)
     }
 }
 
+// Finish the backend representation of the methods.
+
+void
+Interface_type::finish_backend_methods(Gogo* gogo)
+{
+  if (!this->interface_type()->is_empty())
+    {
+      const Typed_identifier_list* methods = this->methods();
+      if (methods != NULL)
+       {
+         for (Typed_identifier_list::const_iterator p = methods->begin();
+              p != methods->end();
+              ++p)
+           p->type()->get_backend(gogo);
+       }
+    }
+}
+
 // The type of an interface type descriptor.
 
 Type*
@@ -7751,7 +7988,7 @@ Named_type::convert(Gogo* gogo)
       {
        std::vector<Backend::Btyped_identifier> bfields;
        get_backend_struct_fields(gogo, base->struct_type()->fields(),
-                                 &bfields);
+                                 true, &bfields);
        if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
          bt = gogo->backend()->error_type();
       }
@@ -7761,7 +7998,7 @@ Named_type::convert(Gogo* gogo)
       // Slice types were completed in create_placeholder.
       if (!base->is_slice_type())
        {
-         Btype* bet = base->array_type()->get_backend_element(gogo);
+         Btype* bet = base->array_type()->get_backend_element(gogo, true);
          Bexpression* blen = base->array_type()->get_backend_length(gogo);
          if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen))
            bt = gogo->backend()->error_type();
@@ -7893,7 +8130,7 @@ Named_type::create_placeholder(Gogo* gogo)
       // because we can fill them in completely here with the final
       // size.
       std::vector<Backend::Btyped_identifier> bfields;
-      get_backend_slice_fields(gogo, base->array_type(), &bfields);
+      get_backend_slice_fields(gogo, base->array_type(), true, &bfields);
       if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
        this->named_btype_ = gogo->backend()->error_type();
     }
@@ -7904,7 +8141,8 @@ Named_type::create_placeholder(Gogo* gogo)
       // because we can fill them in completely here with the final
       // size.
       std::vector<Backend::Btyped_identifier> bfields;
-      get_backend_interface_fields(gogo, base->interface_type(), &bfields);
+      get_backend_interface_fields(gogo, base->interface_type(), true,
+                                  &bfields);
       if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
        this->named_btype_ = gogo->backend()->error_type();
     }
@@ -7963,9 +8201,33 @@ Named_type::do_get_backend(Gogo* gogo)
     case TYPE_NIL:
     case TYPE_MAP:
     case TYPE_CHANNEL:
+      return bt;
+
     case TYPE_STRUCT:
+      if (!this->seen_in_get_backend_)
+       {
+         this->seen_in_get_backend_ = true;
+         base->struct_type()->finish_backend_fields(gogo);
+         this->seen_in_get_backend_ = false;
+       }
+      return bt;
+
     case TYPE_ARRAY:
+      if (!this->seen_in_get_backend_)
+       {
+         this->seen_in_get_backend_ = true;
+         base->array_type()->finish_backend_element(gogo);
+         this->seen_in_get_backend_ = false;
+       }
+      return bt;
+
     case TYPE_INTERFACE:
+      if (!this->seen_in_get_backend_)
+       {
+         this->seen_in_get_backend_ = true;
+         base->interface_type()->finish_backend_methods(gogo);
+         this->seen_in_get_backend_ = false;
+       }
       return bt;
 
     case TYPE_FUNCTION: