Patchwork Go patch committed: Rewrite conversion of named types

login
register
mail settings
Submitter Ian Taylor
Date March 3, 2011, 12:15 a.m.
Message ID <mcrvd013vqf.fsf@google.com>
Download mbox | patch
Permalink /patch/85195/
State New
Headers show

Comments

Ian Taylor - March 3, 2011, 12:15 a.m.
This patch to the Go frontend rewrites the conversion of named types to
GENERIC.  This eliminates some complicated special handling in
Named_type::do_get_tree in favor of a simpler overall approach, in which
we generate a placeholder for a named type, then convert all the types
it depends on, and then complete the type.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian

Patch

diff -r ea2c6e436710 go/expressions.cc
--- a/go/expressions.cc	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/expressions.cc	Wed Mar 02 16:11:13 2011 -0800
@@ -7013,6 +7013,8 @@ 
 	return false;
       if (arg_type->is_abstract())
 	return false;
+      if (arg_type->named_type() != NULL)
+	arg_type->named_type()->convert(this->gogo_);
       tree arg_type_tree = arg_type->get_tree(this->gogo_);
       if (arg_type_tree == error_mark_node)
 	return false;
@@ -7057,6 +7059,8 @@ 
       Type* st = struct_expr->type();
       if (st->struct_type() == NULL)
 	return false;
+      if (st->named_type() != NULL)
+	st->named_type()->convert(this->gogo_);
       tree struct_tree = st->get_tree(this->gogo_);
       gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
       tree field = TYPE_FIELDS(struct_tree);
@@ -8793,10 +8797,21 @@ 
       return error_mark_node;
     }
 
-  // This is to support builtin math functions when using 80387 math.
   tree fndecl = fn;
   if (TREE_CODE(fndecl) == ADDR_EXPR)
     fndecl = TREE_OPERAND(fndecl, 0);
+
+  // Add a type cast in case the type of the function is a recursive
+  // type which refers to itself.
+  if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
+    {
+      tree fnt = fntype->get_tree(gogo);
+      if (fnt == error_mark_node)
+	return error_mark_node;
+      fn = fold_convert_loc(location, fnt, fn);
+    }
+
+  // This is to support builtin math functions when using 80387 math.
   tree excess_type = NULL_TREE;
   if (DECL_P(fndecl)
       && DECL_IS_BUILTIN(fndecl)
@@ -8842,7 +8857,7 @@ 
   // to the correct type.
   if (TREE_TYPE(ret) == ptr_type_node)
     {
-      tree t = this->type()->get_tree(gogo);
+      tree t = this->type()->base()->get_tree(gogo);
       ret = fold_convert_loc(location, t, ret);
     }
 
diff -r ea2c6e436710 go/go.cc
--- a/go/go.cc	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/go.cc	Wed Mar 02 16:11:13 2011 -0800
@@ -118,9 +118,6 @@ 
   // Export global identifiers as appropriate.
   ::gogo->do_exports();
 
-  // Build required interface method tables.
-  ::gogo->build_interface_method_tables();
-
   // Turn short-cut operators (&&, ||) into explicit if statements.
   ::gogo->remove_shortcuts();
 
diff -r ea2c6e436710 go/gogo-tree.cc
--- a/go/gogo-tree.cc	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/gogo-tree.cc	Wed Mar 02 16:11:13 2011 -0800
@@ -640,6 +640,9 @@ 
 void
 Gogo::write_globals()
 {
+  this->convert_named_types();
+  this->build_interface_method_tables();
+
   Bindings* bindings = this->current_bindings();
   size_t count = bindings->size_definitions();
 
diff -r ea2c6e436710 go/gogo.cc
--- a/go/gogo.cc	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/gogo.cc	Wed Mar 02 16:11:13 2011 -0800
@@ -34,7 +34,8 @@ 
     imported_init_fns_(),
     unique_prefix_(),
     unique_prefix_specified_(false),
-    interface_types_()
+    interface_types_(),
+    named_types_are_converted_(false)
 {
   const source_location loc = BUILTINS_LOCATION;
 
@@ -1119,11 +1120,6 @@ 
 int
 Verify_types::type(Type* t)
 {
-  // Don't verify types defined in other packages.
-  Named_type* nt = t->named_type();
-  if (nt != NULL && nt->named_object()->package() != NULL)
-    return TRAVERSE_SKIP_COMPONENTS;
-
   if (!t->verify())
     return TRAVERSE_SKIP_COMPONENTS;
   return TRAVERSE_CONTINUE;
@@ -2520,6 +2516,83 @@ 
 		     this->package_->bindings());
 }
 
+// Find the blocks in order to convert named types defined in blocks.
+
+class Convert_named_types : public Traverse
+{
+ public:
+  Convert_named_types(Gogo* gogo)
+    : Traverse(traverse_blocks),
+      gogo_(gogo)
+  { }
+
+ protected:
+  int
+  block(Block* block);
+
+ private:
+  Gogo* gogo_;
+};
+
+int
+Convert_named_types::block(Block* block)
+{
+  this->gogo_->convert_named_types_in_bindings(block->bindings());
+  return TRAVERSE_CONTINUE;
+}
+
+// Convert all named types to the backend representation.  Since named
+// types can refer to other types, this needs to be done in the right
+// sequence, which is handled by Named_type::convert.  Here we arrange
+// to call that for each named type.
+
+void
+Gogo::convert_named_types()
+{
+  this->convert_named_types_in_bindings(this->globals_);
+  for (Packages::iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    {
+      Package* package = p->second;
+      this->convert_named_types_in_bindings(package->bindings());
+    }
+
+  Convert_named_types cnt(this);
+  this->traverse(&cnt);
+
+  // Make all the builtin named types used for type descriptors, and
+  // then convert them.  They will only be written out if they are
+  // needed.
+  Type::make_type_descriptor_type();
+  Type::make_type_descriptor_ptr_type();
+  Function_type::make_function_type_descriptor_type();
+  Pointer_type::make_pointer_type_descriptor_type();
+  Struct_type::make_struct_type_descriptor_type();
+  Array_type::make_array_type_descriptor_type();
+  Array_type::make_slice_type_descriptor_type();
+  Map_type::make_map_type_descriptor_type();
+  Channel_type::make_chan_type_descriptor_type();
+  Interface_type::make_interface_type_descriptor_type();
+  Type::convert_builtin_named_types(this);
+
+  this->named_types_are_converted_ = true;
+}
+
+// Convert all names types in a set of bindings.
+
+void
+Gogo::convert_named_types_in_bindings(Bindings* bindings)
+{
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    {
+      if ((*p)->is_type())
+	(*p)->type_value()->convert(this);
+    }
+}
+
 // Class Function.
 
 Function::Function(Function_type* type, Function* enclosing, Block* block,
diff -r ea2c6e436710 go/gogo.h
--- a/go/gogo.h	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/gogo.h	Wed Mar 02 16:11:13 2011 -0800
@@ -405,6 +405,20 @@ 
   void
   simplify_thunk_statements();
 
+  // Convert named types to the backend representation.
+  void
+  convert_named_types();
+
+  // Convert named types in a list of bindings.
+  void
+  convert_named_types_in_bindings(Bindings*);
+
+  // True if named types have been converted to the backend
+  // representation.
+  bool
+  named_types_are_converted() const
+  { return this->named_types_are_converted_; }
+
   // Write out the global values.
   void
   write_globals();
@@ -661,6 +675,8 @@ 
   bool unique_prefix_specified_;
   // A list of interface types defined while parsing.
   std::vector<Interface_type*> interface_types_;
+  // Whether named types have been converted.
+  bool named_types_are_converted_;
 };
 
 // A block of statements.
diff -r ea2c6e436710 go/types.cc
--- a/go/types.cc	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/types.cc	Wed Mar 02 16:11:13 2011 -0800
@@ -835,8 +835,9 @@ 
     Type::type_trees.insert(val);
   if (!ins.second && ins.first->second != NULL_TREE)
     {
-      this->tree_ = ins.first->second;
-      return this->tree_;
+      if (gogo != NULL && gogo->named_types_are_converted())
+	this->tree_ = ins.first->second;
+      return ins.first->second;
     }
 
   tree t = this->get_tree_without_hash(gogo);
@@ -850,6 +851,8 @@ 
       // which in turns uses an identical unnamed type.  Use the tree
       // we created earlier and ignore the one we just built.
       t = ins.first->second;
+      if (gogo == NULL || !gogo->named_types_are_converted())
+	return t;
       this->tree_ = t;
     }
 
@@ -874,6 +877,9 @@ 
       if (t == ptr_type_node && this->forward_declaration_type() != NULL)
 	return t;
 
+      if (gogo == NULL || !gogo->named_types_are_converted())
+	return t;
+
       this->tree_ = t;
       go_preserve_from_gc(t);
     }
@@ -961,6 +967,10 @@ 
   return Type::make_struct_type(sfl, bloc);
 }
 
+// A list of builtin named types.
+
+std::vector<Named_type*> Type::named_builtin_types;
+
 // Make a builtin named type.
 
 Named_type*
@@ -968,7 +978,25 @@ 
 {
   source_location bloc = BUILTINS_LOCATION;
   Named_object* no = Named_object::make_type(name, NULL, type, bloc);
-  return no->type_value();
+  Named_type* ret = no->type_value();
+  Type::named_builtin_types.push_back(ret);
+  return ret;
+}
+
+// Convert the named builtin types.
+
+void
+Type::convert_builtin_named_types(Gogo* gogo)
+{
+  for (std::vector<Named_type*>::const_iterator p =
+	 Type::named_builtin_types.begin();
+       p != Type::named_builtin_types.end();
+       ++p)
+    {
+      bool r = (*p)->verify();
+      gcc_assert(r);
+      (*p)->convert(gogo);
+    }
 }
 
 // Return the type of a type descriptor.  We should really tie this to
@@ -3309,20 +3337,10 @@ 
   gcc_assert(fntype != NULL);
   const Typed_identifier_list* results = fntype->results();
   gcc_assert(results != NULL && results->size() > 1);
-
-  Struct_field_list* sfl = new Struct_field_list;
-  for (Typed_identifier_list::const_iterator p = results->begin();
-       p != results->end();
-       ++p)
-    {
-      const std::string name = ((p->name().empty()
-				 || p->name() == Import::import_marker)
-				? "UNNAMED"
-				: p->name());
-      sfl->push_back(Struct_field(Typed_identifier(name, p->type(),
-						   this->call_->location())));
-    }
-  return Type::make_struct_type(sfl, this->call_->location())->get_tree(gogo);
+  tree fntype_tree = fntype->get_tree(gogo);
+  if (fntype_tree == error_mark_node)
+    return error_mark_node;
+  return TREE_TYPE(fntype_tree);
 }
 
 // Make a call result type.
@@ -3782,7 +3800,6 @@ 
 {
   tree field_trees = NULL_TREE;
   tree* pp = &field_trees;
-  bool has_pointer = false;
   for (Struct_field_list::const_iterator p = this->fields_->begin();
        p != this->fields_->end();
        ++p)
@@ -3790,20 +3807,10 @@ 
       std::string name = Gogo::unpack_hidden_name(p->field_name());
       tree name_tree = get_identifier_with_length(name.data(), name.length());
 
-      // Don't follow pointers yet, so that we don't get confused by a
-      // pointer to an array of this struct type.
-      tree field_type_tree;
-      if (p->type()->points_to() != NULL || p->type()->function_type() != NULL)
-	{
-	  field_type_tree = ptr_type_node;
-	  has_pointer = true;
-	}
-      else
-	{
-	  field_type_tree = p->type()->get_tree(gogo);
-	  if (field_type_tree == error_mark_node)
-	    return error_mark_node;
-	}
+      tree field_type_tree = p->type()->get_tree(gogo);
+      if (field_type_tree == error_mark_node)
+	return error_mark_node;
+      gcc_assert(TYPE_SIZE(field_type_tree) != NULL_TREE);
 
       tree field = build_decl(p->location(), FIELD_DECL, name_tree,
 			      field_type_tree);
@@ -3816,35 +3823,9 @@ 
 
   layout_type(type);
 
-  if (has_pointer)
-    {
-      tree field = field_trees;
-      for (Struct_field_list::const_iterator p = this->fields_->begin();
-	   p != this->fields_->end();
-	   ++p, field = DECL_CHAIN(field))
-	{
-	  if (p->type()->points_to() != NULL
-	      || p->type()->function_type() != NULL)
-	    TREE_TYPE(field) = p->type()->get_tree(gogo);
-	}
-    }
-
   return type;
 }
 
-// Make sure that all structs which must be converted to the backend
-// representation before this one are in fact converted.
-
-void
-Struct_type::convert_prerequisites(Gogo* gogo)
-{
-  for (std::vector<Named_type*>::const_iterator p
-	 = this->prerequisites_.begin();
-       p != this->prerequisites_.end();
-       ++p)
-    (*p)->get_tree(gogo);
-}
-
 // Initialize struct fields.
 
 tree
@@ -4487,6 +4468,8 @@ 
       || length_tree == error_mark_node)
     return error_mark_node;
 
+  gcc_assert(TYPE_SIZE(element_type_tree) != NULL_TREE);
+
   length_tree = fold_convert(sizetype, length_tree);
 
   // build_index_type takes the maximum index, which is one less than
@@ -6074,22 +6057,62 @@ 
 Interface_type::do_get_tree(Gogo* gogo)
 {
   if (this->methods_ == NULL)
-    {
-      // At the tree level, use the same type for all empty
-      // interfaces.  This lets us assign them to each other directly
-      // without triggering GIMPLE type errors.
-      tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
-      dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
-      static tree empty_interface;
-      return Gogo::builtin_struct(&empty_interface, "__go_empty_interface",
-				  NULL_TREE, 2,
-				  "__type_descriptor",
-				  dtype,
-				  "__object",
-				  ptr_type_node);
-    }
-
-  return this->fill_in_tree(gogo, make_node(RECORD_TYPE));
+    return Interface_type::empty_type_tree(gogo);
+  else
+    {
+      tree t = Interface_type::non_empty_type_tree(this->location_);
+      return this->fill_in_tree(gogo, t);
+    }
+}
+
+// Return a singleton struct for an empty interface type.  We use the
+// same type for all empty interfaces.  This lets us assign them to
+// each other directly without triggering GIMPLE type errors.
+
+tree
+Interface_type::empty_type_tree(Gogo* gogo)
+{
+  static tree empty_interface;
+  if (empty_interface != NULL_TREE)
+    return empty_interface;
+
+  tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
+  dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
+  return Gogo::builtin_struct(&empty_interface, "__go_empty_interface",
+			      NULL_TREE, 2,
+			      "__type_descriptor",
+			      dtype,
+			      "__object",
+			      ptr_type_node);
+}
+
+// Return a new struct for a non-empty interface type.  The correct
+// values are filled in by fill_in_tree.
+
+tree
+Interface_type::non_empty_type_tree(source_location location)
+{
+  tree ret = make_node(RECORD_TYPE);
+
+  tree field_trees = NULL_TREE;
+  tree* pp = &field_trees;
+
+  tree name_tree = get_identifier("__methods");
+  tree field = build_decl(location, FIELD_DECL, name_tree, ptr_type_node);
+  DECL_CONTEXT(field) = ret;
+  *pp = field;
+  pp = &DECL_CHAIN(field);
+
+  name_tree = get_identifier("__object");
+  field = build_decl(location, FIELD_DECL, name_tree, ptr_type_node);
+  DECL_CONTEXT(field) = ret;
+  *pp = field;
+
+  TYPE_FIELDS(ret) = field_trees;
+
+  layout_type(ret);
+
+  return ret;
 }
 
 // Fill in the tree for an interface type.  This is used for named
@@ -6100,44 +6123,20 @@ 
 {
   gcc_assert(this->methods_ != NULL);
 
-  // Because the methods may refer to the interface type itself, we
-  // need to build the interface type first, and then update the
-  // method pointer later.
-
-  tree field_trees = NULL_TREE;
-  tree* pp = &field_trees;
-
-  tree name_tree = get_identifier("__methods");
-  tree methods_field = build_decl(this->location_, FIELD_DECL, name_tree,
-				  ptr_type_node);
-  DECL_CONTEXT(methods_field) = type;
-  *pp = methods_field;
-  pp = &DECL_CHAIN(methods_field);
-
-  name_tree = get_identifier("__object");
-  tree field = build_decl(this->location_, FIELD_DECL, name_tree,
-			  ptr_type_node);
-  DECL_CONTEXT(field) = type;
-  *pp = field;
-
-  TYPE_FIELDS(type) = field_trees;
-
-  layout_type(type);
-
   // Build the type of the table of methods.
 
   tree method_table = make_node(RECORD_TYPE);
 
   // The first field is a pointer to the type descriptor.
-  name_tree = get_identifier("__type_descriptor");
+  tree name_tree = get_identifier("__type_descriptor");
   tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
   dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
-  field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
+  tree field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
   DECL_CONTEXT(field) = method_table;
   TYPE_FIELDS(method_table) = field;
 
   std::string last_name = "";
-  pp = &DECL_CHAIN(field);
+  tree* pp = &DECL_CHAIN(field);
   for (Typed_identifier_list::const_iterator p = this->methods_->begin();
        p != this->methods_->end();
        ++p)
@@ -6159,7 +6158,10 @@ 
 
   // Update the type of the __methods field from a generic pointer to
   // a pointer to the method table.
-  TREE_TYPE(methods_field) = build_pointer_type(method_table);
+  field = TYPE_FIELDS(type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
+
+  TREE_TYPE(field) = build_pointer_type(method_table);
 
   return type;
 }
@@ -6876,7 +6878,7 @@ 
 class Find_type_use : public Traverse
 {
  public:
-  Find_type_use(Type* find_type)
+  Find_type_use(Named_type* find_type)
     : Traverse(traverse_types),
       find_type_(find_type), found_(false)
   { }
@@ -6892,7 +6894,7 @@ 
 
  private:
   // The type we are looking for.
-  Type* find_type_;
+  Named_type* find_type_;
   // Whether we found the type.
   bool found_;
 };
@@ -6902,11 +6904,12 @@ 
 int
 Find_type_use::type(Type* type)
 {
-  if (this->find_type_ == type)
+  if (type->named_type() != NULL && this->find_type_ == type->named_type())
     {
       this->found_ = true;
       return TRAVERSE_EXIT;
     }
+
   // It's OK if we see a reference to the type in any type which is
   // essentially a pointer: a pointer, a slice, a function, a map, or
   // a channel.
@@ -6940,6 +6943,42 @@ 
       return TRAVERSE_SKIP_COMPONENTS;
     }
 
+  // Otherwise, FIND_TYPE_ depends on TYPE, in the sense that we need
+  // to convert TYPE to the backend representation before we convert
+  // FIND_TYPE_.
+  if (type->named_type() != NULL)
+    {
+      switch (type->base()->classification())
+	{
+	case Type::TYPE_ERROR:
+	case Type::TYPE_BOOLEAN:
+	case Type::TYPE_INTEGER:
+	case Type::TYPE_FLOAT:
+	case Type::TYPE_COMPLEX:
+	case Type::TYPE_STRING:
+	case Type::TYPE_NIL:
+	  break;
+
+	case Type::TYPE_ARRAY:
+	case Type::TYPE_STRUCT:
+	  this->find_type_->add_dependency(type->named_type());
+	  break;
+
+	case Type::TYPE_VOID:
+	case Type::TYPE_SINK:
+	case Type::TYPE_FUNCTION:
+	case Type::TYPE_POINTER:
+	case Type::TYPE_CALL_MULTIPLE_RESULT:
+	case Type::TYPE_MAP:
+	case Type::TYPE_CHANNEL:
+	case Type::TYPE_INTERFACE:
+	case Type::TYPE_NAMED:
+	case Type::TYPE_FORWARD:
+	default:
+	  gcc_unreachable();
+	}
+    }
+
   return TRAVERSE_CONTINUE;
 }
 
@@ -6995,36 +7034,6 @@ 
 	return false;
     }
 
-  // If this is a struct, then if any of the fields of the struct
-  // themselves have struct type, or array of struct type, then this
-  // struct must be converted to the backend representation before the
-  // field's type is converted.  That may seem backward, but it works
-  // because if the field's type refers to this one, e.g., via a
-  // pointer, then the conversion process will pick up the half-built
-  // struct and do the right thing.
-  if (this->struct_type() != NULL)
-    {
-      const Struct_field_list* fields = this->struct_type()->fields();
-      for (Struct_field_list::const_iterator p = fields->begin();
-	   p != fields->end();
-	   ++p)
-	{
-	  Struct_type* st = p->type()->struct_type();
-	  if (st != NULL)
-	    st->add_prerequisite(this);
-	  else
-	    {
-	      Array_type* at = p->type()->array_type();
-	      if (at != NULL && !at->is_open_array_type())
-		{
-		  st = at->element_type()->struct_type();
-		  if (st != NULL)
-		    st->add_prerequisite(this);
-		}
-	    }
-	}
-    }
-
   return true;
 }
 
@@ -7074,22 +7083,32 @@ 
   return ret;
 }
 
-// Get a tree for a named type.
-
-tree
-Named_type::do_get_tree(Gogo* gogo)
-{
-  if (this->is_error_)
-    return error_mark_node;
-
-  // Go permits types to refer to themselves in various ways.  Break
-  // the recursion here.
-  tree t;
-  switch (this->type_->forwarded()->classification())
-    {
-    case TYPE_ERROR:
-      return error_mark_node;
-
+// Convert a named type to the backend representation.  In order to
+// get dependencies right, we fill in a dummy structure for this type,
+// then convert all the dependencies, then complete this type.  When
+// this function is complete, the size of the type is known.
+
+void
+Named_type::convert(Gogo* gogo)
+{
+  if (this->is_error_ || this->is_converted_)
+    return;
+
+  this->create_placeholder(gogo);
+
+  // Convert all the dependencies.  If they refer indirectly back to
+  // this type, they will pick up the intermediate tree we just
+  // created.
+  for (std::vector<Named_type*>::const_iterator p = this->dependencies_.begin();
+       p != this->dependencies_.end();
+       ++p)
+    (*p)->convert(gogo);
+
+  // Complete this type.
+  tree t = this->named_tree_;
+  Type* base = this->type_->base();
+  switch (base->classification())
+    {
     case TYPE_VOID:
     case TYPE_BOOLEAN:
     case TYPE_INTEGER:
@@ -7097,163 +7116,272 @@ 
     case TYPE_COMPLEX:
     case TYPE_STRING:
     case TYPE_NIL:
-      // These types can not refer to themselves.
+      break;
+
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      break;
+
+    case TYPE_FUNCTION:
+    case TYPE_POINTER:
+      // The size of these types is already correct.
+      break;
+
+    case TYPE_STRUCT:
+      t = base->struct_type()->fill_in_tree(gogo, t);
+      break;
+
+    case TYPE_ARRAY:
+      if (!base->is_open_array_type())
+	t = base->array_type()->fill_in_array_tree(gogo, t);
+      break;
+
+    case TYPE_INTERFACE:
+      if (!base->interface_type()->is_empty())
+	t = base->interface_type()->fill_in_tree(gogo, t);
+      break;
+
+    case TYPE_ERROR:
+      return;
+
+    default:
+    case TYPE_SINK:
+    case TYPE_CALL_MULTIPLE_RESULT:
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
+      gcc_unreachable();
+    }
+
+  this->named_tree_ = t;
+
+  if (t == error_mark_node)
+    this->is_error_ = true;
+  else
+    gcc_assert(TYPE_SIZE(t) != NULL_TREE);
+
+  this->is_converted_ = true;
+}
+
+// Create the placeholder for a named type.  This is the first step in
+// converting to the backend representation.
+
+void
+Named_type::create_placeholder(Gogo* gogo)
+{
+  if (this->is_error_)
+    this->named_tree_ = error_mark_node;
+
+  if (this->named_tree_ != NULL_TREE)
+    return;
+
+  // Create the structure for this type.  Note that because we call
+  // base() here, we don't attempt to represent a named type defined
+  // as another named type.  Instead both named types will point to
+  // different base representations.
+  Type* base = this->type_->base();
+  tree t;
+  switch (base->classification())
+    {
+    case TYPE_ERROR:
+      this->is_error_ = true;
+      this->named_tree_ = error_mark_node;
+      return;
+
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      // These are simple basic types, we can just create them
+      // directly.
+      t = Type::get_named_type_tree(gogo, base);
+      if (t == error_mark_node)
+	{
+	  this->is_error_ = true;
+	  this->named_tree_ = error_mark_node;
+	  return;
+	}
+      t = build_variant_type_copy(t);
+      break;
+
     case TYPE_MAP:
     case TYPE_CHANNEL:
       // All maps and channels have the same type in GENERIC.
-      t = Type::get_named_type_tree(gogo, this->type_);
+      t = Type::get_named_type_tree(gogo, base);
       if (t == error_mark_node)
-	return error_mark_node;
-      // Build a copy to set TYPE_NAME.
+	{
+	  this->is_error_ = true;
+	  this->named_tree_ = error_mark_node;
+	  return;
+	}
       t = build_variant_type_copy(t);
       break;
 
     case TYPE_FUNCTION:
-      // GENERIC can't handle a pointer to a function type whose
-      // return type is a pointer to the function type itself.  It
-      // goes into an infinite loop when walking the types.
-      if (this->seen_ > 0)
-	{
-	  Function_type* fntype = this->type_->function_type();
-	  if (fntype->results() != NULL
-	      && fntype->results()->size() == 1
-	      && fntype->results()->front().type()->forwarded() == this)
-	    return ptr_type_node;
-
-	  // We can legitimately see ourselves here twice when a named
-	  // type is defined using a struct which refers to the named
-	  // type.  If we see ourselves too often we are in a loop.
-	  if (this->seen_ > 3)
-	    return ptr_type_node;
-	}
-      ++this->seen_;
-      t = Type::get_named_type_tree(gogo, this->type_);
-      --this->seen_;
-      if (t == error_mark_node)
-	return error_mark_node;
-      t = build_variant_type_copy(t);
+    case TYPE_POINTER:
+      t = build_variant_type_copy(ptr_type_node);
       break;
 
-    case TYPE_POINTER:
-      // Don't recur infinitely if a pointer type refers to itself.
-      // Ideally we would build a circular data structure here, but
-      // GENERIC can't handle them.
-      if (this->seen_ > 0)
-	{
-	  if (this->type_->points_to()->forwarded() == this)
-	    return ptr_type_node;
-
-	  if (this->seen_ > 3)
-	    return ptr_type_node;
-	}
-      ++this->seen_;
-      t = Type::get_named_type_tree(gogo, this->type_);
-      --this->seen_;
-      if (t == error_mark_node)
-	return error_mark_node;
-      t = build_variant_type_copy(t);
+    case TYPE_STRUCT:
+      t = make_node(RECORD_TYPE);
       break;
 
-    case TYPE_STRUCT:
-      // If there are structs which must be converted first, do them.
-      if (this->seen_ == 0)
-	{
-	  ++this->seen_;
-	  this->type_->struct_type()->convert_prerequisites(gogo);
-	  --this->seen_;
-	}
-
-      if (this->named_tree_ != NULL_TREE)
-	return this->named_tree_;
-
-      t = make_node(RECORD_TYPE);
-      this->named_tree_ = t;
-      t = this->type_->struct_type()->fill_in_tree(gogo, t);
-      if (t == error_mark_node)
-	{
-	  this->named_tree_ = error_mark_node;
-	  return error_mark_node;
-	}
+    case TYPE_ARRAY:
+      if (base->is_open_array_type())
+	t = gogo->slice_type_tree(void_type_node);
+      else
+	t = make_node(ARRAY_TYPE);
       break;
 
-    case TYPE_ARRAY:
-      if (this->named_tree_ != NULL_TREE)
-	return this->named_tree_;
-      if (!this->is_open_array_type())
-	{
-	  t = make_node(ARRAY_TYPE);
-	  this->named_tree_ = t;
-	  t = this->type_->array_type()->fill_in_array_tree(gogo, t);
+    case TYPE_INTERFACE:
+      if (base->interface_type()->is_empty())
+	{
+	  t = Interface_type::empty_type_tree(gogo);
+	  t = build_variant_type_copy(t);
 	}
       else
 	{
-	  t = gogo->slice_type_tree(void_type_node);
-	  this->named_tree_ = t;
-	  t = this->type_->array_type()->fill_in_slice_tree(gogo, t);
-	}
-      if (t == error_mark_node)
-	return error_mark_node;
-      t = build_variant_type_copy(t);
+	  source_location loc = base->interface_type()->location();
+	  t = Interface_type::non_empty_type_tree(loc);
+	}
       break;
 
-    case TYPE_INTERFACE:
-      if (this->type_->interface_type()->is_empty())
-	{
-	  t = Type::get_named_type_tree(gogo, this->type_);
-	  if (t == error_mark_node)
-	    return error_mark_node;
-	  t = build_variant_type_copy(t);
-	}
-      else
-	{
-	  if (this->named_tree_ != NULL_TREE)
-	    return this->named_tree_;
-	  t = make_node(RECORD_TYPE);
-	  this->named_tree_ = t;
-	  t = this->type_->interface_type()->fill_in_tree(gogo, t);
-	  if (t == error_mark_node)
-	    {
-	      this->named_tree_ = error_mark_node;
-	      return error_mark_node;
-	    }
-	}
-      break;
-
-    case TYPE_NAMED:
-      {
-	// When a named type T1 is defined as another named type T2,
-	// the definition must simply be "type T1 T2".  If the
-	// definition of T2 may refer to T1, then we must simply
-	// return the type for T2 here.  It's not precisely correct,
-	// but it's as close as we can get with GENERIC.
-	++this->seen_;
-	t = Type::get_named_type_tree(gogo, this->type_);
-	--this->seen_;
-	if (this->seen_ > 0)
-	  return t;
-	if (t == error_mark_node)
-	  return error_mark_node;
-	t = build_variant_type_copy(t);
-      }
-      break;
-
-    case TYPE_FORWARD:
-      // An undefined forwarding type.  Make sure the error is
-      // emitted.
-      this->type_->forward_declaration_type()->real_type();
-      return error_mark_node;
-
     default:
     case TYPE_SINK:
     case TYPE_CALL_MULTIPLE_RESULT:
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
       gcc_unreachable();
     }
 
+  // Create the named type.
+
   tree id = this->named_object_->get_id(gogo);
   tree decl = build_decl(this->location_, TYPE_DECL, id, t);
   TYPE_NAME(t) = decl;
 
-  return t;
+  this->named_tree_ = t;
+}
+
+// Get a tree for a named type.
+
+tree
+Named_type::do_get_tree(Gogo* gogo)
+{
+  if (this->is_error_)
+    return error_mark_node;
+
+  tree t = this->named_tree_;
+
+  // FIXME: GOGO can be NULL when called from go_type_for_size, which
+  // is only used for basic types.
+  if (gogo == NULL || !gogo->named_types_are_converted())
+    {
+      // We have not completed converting named types.  NAMED_TREE_ is
+      // a placeholder and we shouldn't do anything further.
+      if (t != NULL_TREE)
+	return t;
+
+      // We don't build dependencies for types whose sizes do not
+      // change or are not relevant, so we may see them here while
+      // converting types.
+      this->create_placeholder(gogo);
+      t = this->named_tree_;
+      gcc_assert(t != NULL_TREE);
+      return t;
+    }
+
+  // We are not converting types.  This should only be called if the
+  // type has already been converted.
+  gcc_assert(this->is_converted_);
+  gcc_assert(t != NULL_TREE && TYPE_SIZE(t) != NULL_TREE);
+
+  // Complete the tree.
+  Type* base = this->type_->base();
+  tree t1;
+  switch (base->classification())
+    {
+    case TYPE_ERROR:
+      return error_mark_node;
+
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+    case TYPE_STRUCT:
+    case TYPE_INTERFACE:
+      return t;
+
+    case TYPE_FUNCTION:
+      // Don't build a circular data structure.  GENERIC can't handle
+      // it.
+      if (this->seen_ > 0)
+	{
+	  this->is_circular_ = true;
+	  return ptr_type_node;
+	}
+      ++this->seen_;
+      t1 = Type::get_named_type_tree(gogo, base);
+      --this->seen_;
+      if (t1 == error_mark_node)
+	return error_mark_node;
+      if (this->is_circular_)
+	t1 = ptr_type_node;
+      gcc_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE);
+      gcc_assert(TREE_CODE(t1) == POINTER_TYPE);
+      TREE_TYPE(t) = TREE_TYPE(t1);
+      return t;
+
+    case TYPE_POINTER:
+      // Don't build a circular data structure. GENERIC can't handle
+      // it.
+      if (this->seen_ > 0)
+	{
+	  this->is_circular_ = true;
+	  return ptr_type_node;
+	}
+      ++this->seen_;
+      t1 = Type::get_named_type_tree(gogo, base);
+      --this->seen_;
+      if (t1 == error_mark_node)
+	return error_mark_node;
+      if (this->is_circular_)
+	t1 = ptr_type_node;
+      gcc_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE);
+      gcc_assert(TREE_CODE(t1) == POINTER_TYPE);
+      TREE_TYPE(t) = TREE_TYPE(t1);
+      return t;
+
+    case TYPE_ARRAY:
+      if (base->is_open_array_type())
+	{
+	  if (this->seen_ > 0)
+	    return t;
+	  else
+	    {
+	      ++this->seen_;
+	      t = base->array_type()->fill_in_slice_tree(gogo, t);
+	      --this->seen_;
+	    }
+	}
+      return t;
+
+    default:
+    case TYPE_SINK:
+    case TYPE_CALL_MULTIPLE_RESULT:
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
+      gcc_unreachable();
+    }
+
+  gcc_unreachable();
 }
 
 // Build a type descriptor for a named type.
diff -r ea2c6e436710 go/types.h
--- a/go/types.h	Thu Feb 24 07:42:07 2011 -0800
+++ b/go/types.h	Wed Mar 02 16:11:13 2011 -0800
@@ -799,6 +799,10 @@ 
   check_make_expression(Expression_list* args, source_location location)
   { return this->do_check_make_expression(args, location); }
 
+  // Convert the builtin named types.
+  static void
+  convert_builtin_named_types(Gogo*);
+
   // Return a tree representing this type.
   tree
   get_tree(Gogo*);
@@ -1082,6 +1086,9 @@ 
 
   static Type_trees type_trees;
 
+  // A list of builtin named types.
+  static std::vector<Named_type*> named_builtin_types;
+
   // The type classification.
   Type_classification classification_;
   // The tree representation of the type, once it has been determined.
@@ -1605,6 +1612,9 @@ 
   Function_type*
   copy_with_receiver(Type*) const;
 
+  static Type*
+  make_function_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1636,9 +1646,6 @@ 
   do_export(Export*) const;
 
  private:
-  static Type*
-  make_function_type_descriptor_type();
-
   Expression*
   type_descriptor_params(Type*, const Typed_identifier*,
 			 const Typed_identifier_list*);
@@ -1680,6 +1687,9 @@ 
   static Pointer_type*
   do_import(Import*);
 
+  static Type*
+  make_pointer_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1710,9 +1720,6 @@ 
   do_export(Export*) const;
 
  private:
-  static Type*
-  make_pointer_type_descriptor_type();
-
   // The type to which this type points.
   Type* to_type_;
 };
@@ -1841,8 +1848,7 @@ 
  public:
   Struct_type(Struct_field_list* fields, source_location location)
     : Type(TYPE_STRUCT),
-      fields_(fields), location_(location), all_methods_(NULL),
-      prerequisites_()
+      fields_(fields), location_(location), all_methods_(NULL)
   { }
 
   // Return the field NAME.  This only looks at local fields, not at
@@ -1937,16 +1943,8 @@ 
   tree
   fill_in_tree(Gogo*, tree);
 
-  // Note that a struct must be converted to the backend
-  // representation before we convert this struct.
-  void
-  add_prerequisite(Named_type* nt)
-  { this->prerequisites_.push_back(nt); }
-
-  // If there are any structs which must be converted to the backend
-  // representation before this one, convert them.
-  void
-  convert_prerequisites(Gogo*);
+  static Type*
+  make_struct_type_descriptor_type();
 
  protected:
   int
@@ -1992,25 +1990,12 @@ 
 			source_location, Saw_named_type*,
 			unsigned int* depth) const;
 
-  static Type*
-  make_struct_type_descriptor_type();
-
   // The fields of the struct.
   Struct_field_list* fields_;
   // The place where the struct was declared.
   source_location location_;
   // If this struct is unnamed, a list of methods.
   Methods* all_methods_;
-  // A list of structs which must be converted to the backend
-  // representation before this struct can be converted.  This is for
-  // cases like
-  //   type S1 { p *S2 }
-  //   type S2 { s S1 }
-  // where we must start converting S2 before we start converting S1.
-  // That is because we can fully convert S1 before S2 is complete,
-  // but we can not fully convert S2 before S1 is complete.  If we
-  // start converting S1 first, we won't be able to convert S2.
-  std::vector<Named_type*> prerequisites_;
 };
 
 // The type of an array.
@@ -2066,6 +2051,12 @@ 
   tree
   fill_in_slice_tree(Gogo*, tree);
 
+  static Type*
+  make_array_type_descriptor_type();
+
+  static Type*
+  make_slice_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse* traverse);
@@ -2114,12 +2105,6 @@ 
   tree
   get_length_tree(Gogo*);
 
-  Type*
-  make_array_type_descriptor_type();
-
-  Type*
-  make_slice_type_descriptor_type();
-
   Expression*
   array_type_descriptor(Gogo*, Named_type*);
 
@@ -2162,6 +2147,9 @@ 
   static Map_type*
   do_import(Import*);
 
+  static Type*
+  make_map_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse*);
@@ -2202,9 +2190,6 @@ 
   do_export(Export*) const;
 
  private:
-  static Type*
-  make_map_type_descriptor_type();
-
   // The key type.
   Type* key_type_;
   // The value type.
@@ -2248,6 +2233,9 @@ 
   static Channel_type*
   do_import(Import*);
 
+  static Type*
+  make_chan_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse* traverse)
@@ -2286,9 +2274,6 @@ 
   do_export(Export*) const;
 
  private:
-  static Type*
-  make_chan_type_descriptor_type();
-
   // Whether this channel can send data.
   bool may_send_;
   // Whether this channel can receive data.
@@ -2308,6 +2293,11 @@ 
       methods_(methods), location_(location)
   { gcc_assert(methods == NULL || !methods->empty()); }
 
+  // The location where the interface type was defined.
+  source_location
+  location() const
+  { return this->location_; }
+
   // Return whether this is an empty interface.
   bool
   is_empty() const
@@ -2361,10 +2351,21 @@ 
   static Interface_type*
   do_import(Import*);
 
+  // Make a struct for an empty interface type.
+  static tree
+  empty_type_tree(Gogo*);
+
+  // Make a struct for non-empty interface type.
+  static tree
+  non_empty_type_tree(source_location);
+
   // Fill in the fields for a named interface type.
   tree
   fill_in_tree(Gogo*, tree);
 
+  static Type*
+  make_interface_type_descriptor_type();
+
  protected:
   int
   do_traverse(Traverse*);
@@ -2395,9 +2396,6 @@ 
   do_export(Export*) const;
 
  private:
-  static Type*
-  make_interface_type_descriptor_type();
-
   // The list of methods associated with the interface.  This will be
   // NULL for the empty interface.
   Typed_identifier_list* methods_;
@@ -2419,8 +2417,9 @@ 
       named_object_(named_object), in_function_(NULL), type_(type),
       local_methods_(NULL), all_methods_(NULL),
       interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
-      location_(location), named_tree_(NULL), is_visible_(true),
-      is_error_(false), seen_(0)
+      location_(location), named_tree_(NULL), dependencies_(),
+      is_visible_(true), is_error_(false), is_converted_(false),
+      is_circular_(false), seen_(0)
   { }
 
   // Return the associated Named_object.  This holds the actual name.
@@ -2493,6 +2492,12 @@ 
   is_builtin() const
   { return this->location_ == BUILTINS_LOCATION; }
 
+  // Whether this is a circular type: a pointer or function type that
+  // refers to itself, which is not possible in C.
+  bool
+  is_circular() const
+  { return this->is_circular_; }
+
   // Return the base type for this type.
   Type*
   named_base();
@@ -2567,6 +2572,12 @@ 
   bool
   named_type_has_hidden_fields(std::string* reason) const;
 
+  // Note that a type must be converted to the backend representation
+  // before we convert this type.
+  void
+  add_dependency(Named_type* nt)
+  { this->dependencies_.push_back(nt); }
+
   // Export the type.
   void
   export_named_type(Export*, const std::string& name) const;
@@ -2575,6 +2586,10 @@ 
   static void
   import_named_type(Import*, Named_type**);
 
+  // Initial conversion to backend representation.
+  void
+  convert(Gogo*);
+
  protected:
   int
   do_traverse(Traverse* traverse)
@@ -2618,6 +2633,10 @@ 
   do_export(Export*) const;
 
  private:
+  // Create the placeholder during conversion.
+  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,
@@ -2647,6 +2666,14 @@ 
   // The tree for this type while converting to GENERIC.  This is used
   // to avoid endless recursion when a named type refers to itself.
   tree named_tree_;
+  // A list of types which must be converted to the backend
+  // representation before this type can be converted.  This is for
+  // cases like
+  //   type S1 { p *S2 }
+  //   type S2 { s S1 }
+  // where we can't convert S2 to the backend representation unless we
+  // have converted S1.
+  std::vector<Named_type*> dependencies_;
   // Whether this type is visible.  This is false if this type was
   // created because it was referenced by an imported object, but the
   // type itself was not exported.  This will always be true for types
@@ -2654,6 +2681,12 @@ 
   bool is_visible_;
   // Whether this type is erroneous.
   bool is_error_;
+  // Whether this type has been converted to the backend
+  // representation.
+  bool is_converted_;
+  // Whether this is a pointer or function type which refers to the
+  // type itself.
+  bool is_circular_;
   // In a recursive operation such as has_hidden_fields, this flag is
   // used to prevent infinite recursion when a type refers to itself.
   // This is mutable because it is always reset to false when the