The gccgo frontend was crashing on code like

type T1 struct { F1 *[1]T2 }
type T2 struct { X int }

It needed to know the size of T2 before it was computed.  This patch
fixes the problem.  I added a testcase as bug417.go in the master Go
testsuite, which I will merged into the gccgo testsuite later.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

diff -r e00e83337364 go/expressions.cc
--- a/go/expressions.cc	Wed Feb 15 14:29:00 2012 -0800
+++ b/go/expressions.cc	Wed Feb 15 22:31:03 2012 -0800
@@ -522,8 +522,8 @@
       // first field is just the type descriptor of the object.
       go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
 			"__type_descriptor") == 0);
-      go_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor));
-      elt->value = rhs_type_descriptor;
+      elt->value = fold_convert_loc(location.gcc_location(),
+				    TREE_TYPE(field), rhs_type_descriptor);
     }
   else
     {
diff -r e00e83337364 go/gogo.cc
--- a/go/gogo.cc	Wed Feb 15 14:29:00 2012 -0800
+++ b/go/gogo.cc	Wed Feb 15 22:31:03 2012 -0800
@@ -2929,8 +2929,6 @@
 
   Runtime::convert_types(this);
 
-  Function_type::convert_types(this);
-
   this->named_types_are_converted_ = true;
 }
 
diff -r e00e83337364 go/types.cc
--- a/go/types.cc	Wed Feb 15 14:29:00 2012 -0800
+++ b/go/types.cc	Wed Feb 15 22:31:03 2012 -0800
@@ -34,10 +34,28 @@
 #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 @@
 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 @@
   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 @@
 {
   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 @@
 {
   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 @@
 {
   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 @@
 
       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 @@
 // 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 @@
 					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 @@
 
 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 @@
        ++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 @@
 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 @@
 {
   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 @@
 // 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 @@
   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 @@
 // Return the backend representation of the element type.
 
 Btype*
-Array_type::get_backend_element(Gogo* gogo)
-{
-  return this->element_type_->get_backend(gogo);
+Array_type::get_backend_element(Gogo* gogo, bool use_placeholder)
+{
+  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 @@
   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 @@
 
 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 @@
        ++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 @@
       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 @@
     }
 }
 
+// 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 @@
       {
 	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 @@
       // 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 @@
       // 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 @@
       // 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 @@
     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:
diff -r e00e83337364 go/types.h
--- a/go/types.h	Wed Feb 15 14:29:00 2012 -0800
+++ b/go/types.h	Wed Feb 15 22:31:03 2012 -0800
@@ -852,6 +852,16 @@
   Btype*
   get_backend(Gogo*);
 
+  // Return a placeholder for the backend representation of the type.
+  // This will return a type of the correct size, but for which some
+  // of the fields may still need to be completed.
+  Btype*
+  get_backend_placeholder(Gogo*);
+
+  // Finish the backend representation of a placeholder.
+  void
+  finish_backend(Gogo*);
+
   // Build a type descriptor entry for this type.  Return a pointer to
   // it.  The location is the location which causes us to need the
   // entry.
@@ -1179,6 +1189,9 @@
 
   // 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_;
@@ -1730,10 +1743,6 @@
   Function_type*
   copy_with_receiver(Type*) const;
 
-  // Finishing converting function types.
-  static void
-  convert_types(Gogo*);
-
   static Type*
   make_function_type_descriptor_type();
 
@@ -1773,16 +1782,6 @@
   type_descriptor_params(Type*, const Typed_identifier*,
 			 const Typed_identifier_list*);
 
-  Btype*
-  get_function_backend(Gogo*);
-
-  // A list of function types with multiple results and their
-  // placeholder backend representations, used to postpone building
-  // the structs we use for multiple results until all types are
-  // converted.
-  typedef std::vector<std::pair<Function_type*, Btype*> > Placeholders;
-  static Placeholders placeholders;
-
   // The receiver name and type.  This will be NULL for a normal
   // function, non-NULL for a method.
   Typed_identifier* receiver_;
@@ -2079,6 +2078,10 @@
   bool
   backend_field_offset(Gogo*, unsigned int index, unsigned int* poffset);
 
+  // Finish the backend representation of all the fields.
+  void
+  finish_backend_fields(Gogo*);
+
   // Import a struct type.
   static Struct_type*
   do_import(Import*);
@@ -2193,12 +2196,16 @@
 
   // Return the backend representation of the element type.
   Btype*
-  get_backend_element(Gogo*);
+  get_backend_element(Gogo*, bool use_placeholder);
 
   // Return the backend representation of the length.
   Bexpression*
   get_backend_length(Gogo*);
 
+  // Finish the backend representation of the element type.
+  void
+  finish_backend_element(Gogo*);
+
   static Type*
   make_array_type_descriptor_type();
 
@@ -2521,6 +2528,10 @@
   static Btype*
   get_backend_empty_interface_type(Gogo*);
 
+  // Finish the backend representation of the method types.
+  void
+  finish_backend_methods(Gogo*);
+
   static Type*
   make_interface_type_descriptor_type();
 

Reply via email to