Patchwork [gccgo] Rewrite handling of types that refer to themselves

login
register
mail settings
Submitter Ian Taylor
Date Sept. 8, 2010, 12:13 a.m.
Message ID <mcriq2hm6rt.fsf@google.com>
Download mbox | patch
Permalink /patch/64082/
State New
Headers show

Comments

Ian Taylor - Sept. 8, 2010, 12:13 a.m.
In Go there are several ways that a type can refer directly to itself,
as in
	type P *P
The current code tries to handle all those cases in the various
different types implementations.  I rewrote it to unify the handling at
the place where the self-reference can occur: a named type.  This avoids
certain obscure cases in which the compiler would otherwise go into an
infinite recursive loop.  Committed to gccgo branch.

Ian

Patch

diff -r 765edd916c29 go/types.cc
--- a/go/types.cc	Thu Sep 02 07:49:54 2010 -0700
+++ b/go/types.cc	Tue Sep 07 17:04:50 2010 -0700
@@ -787,21 +787,15 @@ 
   return this->tree_;
 }
 
-// Store an incomplete type tree during construction.
-
-void
-Type::set_incomplete_type_tree(tree incomplete)
-{
-  gcc_assert(this->tree_ == NULL);
-  this->tree_ = incomplete;
-}
-
 // Return a tree representing a zero initialization for this type.
 
 tree
 Type::get_init_tree(Gogo* gogo, bool is_clear)
 {
-  return this->do_init_tree(gogo, is_clear);
+  tree type_tree = this->get_tree(gogo);
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+  return this->do_get_init_tree(gogo, type_tree, is_clear);
 }
 
 // Any type which supports the builtin make function must implement
@@ -921,7 +915,7 @@ 
   { return error_mark_node; }
 
   tree
-  do_init_tree(Gogo*, bool)
+  do_get_init_tree(Gogo*, tree, bool)
   { return error_mark_node; }
 
   void
@@ -959,7 +953,7 @@ 
   { return void_type_node; }
 
   tree
-  do_init_tree(Gogo*, bool)
+  do_get_init_tree(Gogo*, tree, bool)
   { gcc_unreachable(); }
 
   void
@@ -997,8 +991,8 @@ 
   { return boolean_type_node; }
 
   tree
-  do_init_tree(Gogo*, bool is_clear)
-  { return is_clear ? NULL : boolean_false_node; }
+  do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+  { return is_clear ? NULL : fold_convert(type_tree, boolean_false_node); }
 
   void
   do_type_descriptor_decl(Gogo* gogo, Named_type* name, tree* pdecl);
@@ -1167,9 +1161,9 @@ 
 }
 
 tree
-Integer_type::do_init_tree(Gogo* gogo, bool is_clear)
-{
-  return is_clear ? NULL : build_int_cst(this->get_tree(gogo), 0);
+Integer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  return is_clear ? NULL : build_int_cst(type_tree, 0);
 }
 
 // The type descriptor for an integer type.  Integer types are always
@@ -1321,14 +1315,13 @@ 
 }
 
 tree
-Float_type::do_init_tree(Gogo* gogo, bool is_clear)
+Float_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  tree type = this->get_tree(gogo);
   REAL_VALUE_TYPE r;
-  real_from_integer(&r, TYPE_MODE(type), 0, 0, 0);
-  return build_real(type, r);
+  real_from_integer(&r, TYPE_MODE(type_tree), 0, 0, 0);
+  return build_real(type_tree, r);
 }
 
 // The type descriptor for a float type.  Float types are always named.
@@ -1481,15 +1474,14 @@ 
 // Zero initializer.
 
 tree
-Complex_type::do_init_tree(Gogo* gogo, bool is_clear)
+Complex_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  tree type = this->get_tree(gogo);
   REAL_VALUE_TYPE r;
-  real_from_integer(&r, TYPE_MODE(TREE_TYPE(type)), 0, 0, 0);
-  return build_complex(type, build_real(TREE_TYPE(type), r),
-		       build_real(TREE_TYPE(type), r));
+  real_from_integer(&r, TYPE_MODE(TREE_TYPE(type_tree)), 0, 0, 0);
+  return build_complex(type_tree, build_real(TREE_TYPE(type_tree), r),
+		       build_real(TREE_TYPE(type_tree), r));
 }
 
 // The type descriptor for a complex type.  Complex types are always
@@ -1594,12 +1586,11 @@ 
 // We initialize a string to { NULL, 0 }.
 
 tree
-String_type::do_init_tree(Gogo* gogo, bool is_clear)
+String_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL_TREE;
 
-  tree type_tree = this->get_tree(gogo);
   gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
 
   VEC(constructor_elt, gc)* init = VEC_alloc(constructor_elt, gc, 2);
@@ -1700,7 +1691,7 @@ 
   { gcc_unreachable(); }
 
   tree
-  do_init_tree(Gogo*, bool)
+  do_get_init_tree(Gogo*, tree, bool)
   { gcc_unreachable(); }
 
   void
@@ -1979,15 +1970,6 @@ 
 tree
 Function_type::do_get_tree(Gogo* gogo)
 {
-  // A function type can refer to itself indirectly, as in
-  //   type F func() F
-  // A Go function type is represented as a pointer to a GENERIC
-  // function.  Create a pointer node now and fill it in later.
-  tree ret = make_node(POINTER_TYPE);
-  SET_TYPE_MODE(ret, ptr_mode);
-  layout_type(ret);
-  this->set_incomplete_type_tree(ret);
-
   tree args = NULL_TREE;
   tree* pp = &args;
 
@@ -2060,35 +2042,20 @@ 
   if (result == error_mark_node)
     return error_mark_node;
 
-  // A function type whose return type is the function type itself can
-  // not be handled in GENERIC.  Such a type can not be written in C,
-  // but in Go it looks like "type F func() F".  We turn this special
-  // case into a function which returns a generic pointer.
-  if (result == ret)
-    result = ptr_type_node;
-
   tree fntype = build_function_type(result, args);
   if (fntype == error_mark_node)
     return fntype;
 
-  TREE_TYPE(ret) = fntype;
-  TYPE_POINTER_TO(fntype) = ret;
-  if (TYPE_STRUCTURAL_EQUALITY_P(fntype))
-    SET_TYPE_STRUCTURAL_EQUALITY(ret);
-
-  return ret;
+  return build_pointer_type(fntype);
 }
 
 // Functions are initialized to NULL.
 
 tree
-Function_type::do_init_tree(Gogo* gogo, bool is_clear)
+Function_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  tree type_tree = this->get_tree(gogo);
-  if (type_tree == error_mark_node)
-    return error_mark_node;
   return fold_convert(type_tree, null_pointer_node);
 }
 
@@ -2411,13 +2378,10 @@ 
 // Initialize a pointer type.
 
 tree
-Pointer_type::do_init_tree(Gogo* gogo, bool is_clear)
+Pointer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  tree type_tree = this->get_tree(gogo);
-  if (type_tree == error_mark_node)
-    return error_mark_node;
   return fold_convert(type_tree, null_pointer_node);
 }
 
@@ -2513,8 +2477,8 @@ 
   { return ptr_type_node; }
 
   tree
-  do_init_tree(Gogo*, bool is_clear)
-  { return is_clear ? NULL : null_pointer_node; }
+  do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+  { return is_clear ? NULL : fold_convert(type_tree, null_pointer_node); }
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*)
@@ -2560,7 +2524,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool)
+  do_get_init_tree(Gogo*, tree, bool)
   { gcc_unreachable(); }
 
   void
@@ -3019,11 +2983,16 @@ 
 Struct_type::do_get_tree(Gogo* gogo)
 {
   tree type = make_node(RECORD_TYPE);
-  this->set_incomplete_type_tree(type);
-
+  return this->fill_in_tree(gogo, type);
+}
+
+// Fill in the fields for a struct type.
+
+tree
+Struct_type::fill_in_tree(Gogo* gogo, tree type)
+{
   tree field_trees = NULL_TREE;
   tree* pp = &field_trees;
-  gcc_assert(this->fields_ != NULL);
   for (Struct_field_list::const_iterator p = this->fields_->begin();
        p != this->fields_->end();
        ++p)
@@ -3050,12 +3019,8 @@ 
 // Initialize struct fields.
 
 tree
-Struct_type::do_init_tree(Gogo* gogo, bool is_clear)
-{
-  tree type_tree = this->get_tree(gogo);
-  if (type_tree == error_mark_node)
-    return error_mark_node;
-
+Struct_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+{
   if (this->fields_ == NULL || this->fields_->empty())
     {
       if (is_clear)
@@ -3550,7 +3515,12 @@ 
 tree
 Array_type::do_get_tree(Gogo* gogo)
 {
-  if (this->length_ != NULL)
+  if (this->length_ == NULL)
+    {
+      tree struct_type = gogo->slice_type_tree(void_type_node);
+      return this->fill_in_tree(gogo, struct_type);
+    }
+  else
     {
       tree element_type_tree = this->element_type_->get_tree(gogo);
       tree length_tree = this->get_length_tree(gogo);
@@ -3568,48 +3538,47 @@ 
 
       return build_array_type(element_type_tree, index_type);
     }
-  else
-    {
-      // Two different slices of the same element type are really the
-      // same type.  In order to make that valid at the tree level, we
-      // make sure to return the same struct.
-      std::pair<Type*, tree> val(this->element_type_, NULL);
-      std::pair<Array_trees::iterator, bool> ins =
-	Array_type::array_trees.insert(val);
-      if (!ins.second)
-	{
-	  // We've already created a tree type for a slice with this
-	  // element type.
-	  gcc_assert(ins.first->second != NULL_TREE);
-	  return ins.first->second;
-	}
-
-      // A slice type can be recursive, as in "type T []T".  Avoid
-      // infinite recursion by creating the struct first, and then
-      // filling in the element type.
-      tree struct_type = gogo->slice_type_tree(void_type_node);
-      this->set_incomplete_type_tree(struct_type);
-      ins.first->second = struct_type;
-
-      tree element_type_tree = this->element_type_->get_tree(gogo);
-
-      tree field = TYPE_FIELDS(struct_type);
-      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(field))
-		 && TREE_TYPE(TREE_TYPE(field)) == void_type_node);
-      TREE_TYPE(field) = build_pointer_type(element_type_tree);
-
-      return struct_type;
-    }
+}
+
+// Fill in the fields for a slice type.  This is used for named slice
+// types.
+
+tree
+Array_type::fill_in_tree(Gogo* gogo, tree struct_type)
+{
+  gcc_assert(this->length_ == NULL);
+
+  // Two different slices of the same element type are really the same
+  // type.  In order to make that valid at the tree level, we make
+  // sure to return the same struct.
+  std::pair<Type*, tree> val(this->element_type_, NULL);
+  std::pair<Array_trees::iterator, bool> ins =
+    Array_type::array_trees.insert(val);
+  if (!ins.second)
+    {
+      // We've already created a tree type for a slice with this
+      // element type.
+      gcc_assert(ins.first->second != NULL_TREE);
+      return ins.first->second;
+    }
+
+  ins.first->second = struct_type;
+
+  tree element_type_tree = this->element_type_->get_tree(gogo);
+  tree field = TYPE_FIELDS(struct_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+  gcc_assert(POINTER_TYPE_P(TREE_TYPE(field))
+	     && TREE_TYPE(TREE_TYPE(field)) == void_type_node);
+  TREE_TYPE(field) = build_pointer_type(element_type_tree);
+
+  return struct_type;
 }
 
 // Return an initializer for an array type.
 
 tree
-Array_type::do_init_tree(Gogo* gogo, bool is_clear)
-{
-  tree type_tree = this->get_tree(gogo);
-
+Array_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+{
   if (this->length_ == NULL)
     {
       // Open array.
@@ -4170,11 +4139,11 @@ 
 // Initialize a map.
 
 tree
-Map_type::do_init_tree(Gogo* gogo, bool is_clear)
+Map_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  return fold_convert(this->get_tree(gogo), null_pointer_node);
+  return fold_convert(type_tree, null_pointer_node);
 }
 
 // Return an expression for a newly allocated map.
@@ -4344,11 +4313,11 @@ 
 // Initialize a channel variable.
 
 tree
-Channel_type::do_init_tree(Gogo* gogo, bool is_clear)
+Channel_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
-  return fold_convert(this->get_tree(gogo), null_pointer_node);
+  return fold_convert(type_tree, null_pointer_node);
 }
 
 // Handle the builtin function make for a channel.
@@ -4844,14 +4813,13 @@ 
 tree
 Interface_type::do_get_tree(Gogo* gogo)
 {
-  tree dtype = gogo->type_descriptor_type_tree();
-  dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
-
   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 = gogo->type_descriptor_type_tree();
+      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,
@@ -4861,46 +4829,31 @@ 
 				  ptr_type_node);
     }
 
-  // Interface types can have methods which refer to the interface
-  // type itself, so build the type first and then the method table.
-  tree ret = make_node(RECORD_TYPE);
-
-  tree field_trees = NULL_TREE;
-  tree* pp = &field_trees;
-
-  // Create the pointer to the method table but don't fill it in yet.
-  tree mtype = make_node(POINTER_TYPE);
-  SET_TYPE_MODE(mtype, ptr_mode);
-  layout_type(mtype);
-
-  tree name_tree = get_identifier("__methods");
-  tree field = build_decl(this->location_, FIELD_DECL, name_tree, mtype);
-  DECL_CONTEXT(field) = ret;
-  *pp = field;
-  pp = &TREE_CHAIN(field);
-
-  name_tree = get_identifier("__object");
-  field = build_decl(this->location_, FIELD_DECL, name_tree, ptr_type_node);
-  DECL_CONTEXT(field) = ret;
-  *pp = field;
-
-  TYPE_FIELDS(ret) = field_trees;
-
-  layout_type(ret);
-
-  this->set_incomplete_type_tree(ret);
+  return this->fill_in_tree(gogo, make_node(RECORD_TYPE));
+}
+
+// Fill in the tree for an interface type.  This is used for named
+// interface types.
+
+tree
+Interface_type::fill_in_tree(Gogo* gogo, tree type)
+{
+  gcc_assert(this->methods_ != NULL);
 
   // 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");
-  field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
+  tree name_tree = get_identifier("__type_descriptor");
+  tree dtype = gogo->type_descriptor_type_tree();
+  dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
+  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 = &TREE_CHAIN(field);
+  tree* pp = &TREE_CHAIN(field);
   for (Typed_identifier_list::const_iterator p = this->methods_->begin();
        p != this->methods_->end();
        ++p)
@@ -4920,25 +4873,37 @@ 
     }
   layout_type(method_table);
 
-  // Finish up the pointer to the method table.
-  TREE_TYPE(mtype) = method_table;
-  TYPE_POINTER_TO(method_table) = mtype;
-  if (TYPE_STRUCTURAL_EQUALITY_P(method_table))
-    SET_TYPE_STRUCTURAL_EQUALITY(mtype);
-
-  return ret;
+  tree mtype = build_pointer_type(method_table);
+
+  tree field_trees = NULL_TREE;
+  pp = &field_trees;
+
+  name_tree = get_identifier("__methods");
+  field = build_decl(this->location_, FIELD_DECL, name_tree, mtype);
+  DECL_CONTEXT(field) = type;
+  *pp = field;
+  pp = &TREE_CHAIN(field);
+
+  name_tree = get_identifier("__object");
+  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);
+
+  return type;
 }
 
 // Initialization value.
 
 tree
-Interface_type::do_init_tree(Gogo* gogo, bool is_clear)
+Interface_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
 {
   if (is_clear)
     return NULL;
 
-  tree type_tree = this->get_tree(gogo);
-
   VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
   for (tree field = TYPE_FIELDS(type_tree);
        field != NULL_TREE;
@@ -5705,32 +5670,127 @@ 
   if (this->is_error_)
     return error_mark_node;
 
-  tree type_tree = this->type_->get_tree(gogo);
-  if (type_tree != error_mark_node)
-    {
-      tree id = this->named_object_->get_id(gogo);
-
-      // If we are looking at a struct, interface, function, channel
-      // or map, we don't need to make a copy to hold the type.  Doing
-      // this makes it easier for the middle-end to notice when the
-      // types refer to themselves.
-      if (TYPE_NAME(type_tree) == NULL
-	  && (this->type_->struct_type() != NULL
-	      || this->type_->interface_type() != NULL
-	      || this->type_->function_type() != NULL
-	      || this->type_->channel_type() != NULL
-	      || this->type_->map_type() != NULL))
-	;
+  // 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;
+
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      // These types can not refer to themselves.
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      // All maps and channels have the same type in GENERIC.
+      t = this->type_->get_tree(gogo);
+      if (t == error_mark_node)
+	return error_mark_node;
+      // Build a copy to set TYPE_NAME.
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_FUNCTION:
+    case TYPE_POINTER:
+      if (this->seen_)
+	{
+	  // GENERIC can't handle a pointer type which points to
+	  // itself.  It goes into infinite loops when walking the
+	  // types.
+	  return ptr_type_node;
+	}
+      this->seen_ = true;
+      t = this->type_->get_tree(gogo);
+      this->seen_ = false;
+      if (t == error_mark_node)
+	return error_mark_node;
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_STRUCT:
+      if (this->named_tree_ != NULL_TREE)
+	return this->named_tree_;
+      t = make_node(RECORD_TYPE);
+      this->named_tree_ = t;
+      this->type_->struct_type()->fill_in_tree(gogo, t);
+      break;
+
+    case TYPE_ARRAY:
+      if (!this->is_open_array_type())
+	t = this->type_->get_tree(gogo);
       else
 	{
-	  // Make a copy so that we can set TYPE_NAME.
-	  type_tree = build_variant_type_copy(type_tree);
+	  if (this->named_tree_ != NULL_TREE)
+	    return this->named_tree_;
+	  t = gogo->slice_type_tree(void_type_node);
+	  this->named_tree_ = t;
+	  t = this->type_->array_type()->fill_in_tree(gogo, t);
 	}
-
-      tree decl = build_decl(this->location_, TYPE_DECL, id, type_tree);
-      TYPE_NAME(type_tree) = decl;
-    }
-  return type_tree;
+      if (t == error_mark_node)
+	return error_mark_node;
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_INTERFACE:
+      if (this->type_->interface_type()->is_empty())
+	{
+	  t = this->type_->get_tree(gogo);
+	  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);
+	}
+      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.
+	bool was_seen = this->seen_;
+	this->seen_ = true;
+	t = this->type_->get_tree(gogo);
+	this->seen_ = was_seen;
+	if (was_seen)
+	  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:
+      gcc_unreachable();
+    }
+
+  tree id = this->named_object_->get_id(gogo);
+  tree decl = build_decl(this->location_, TYPE_DECL, id, t);
+  TYPE_NAME(t) = decl;
+
+  return t;
 }
 
 // Type descriptor decl.
diff -r 765edd916c29 go/types.h
--- a/go/types.h	Thu Sep 02 07:49:54 2010 -0700
+++ b/go/types.h	Tue Sep 07 17:04:50 2010 -0700
@@ -799,6 +799,12 @@ 
   tree
   get_init_tree(Gogo*, bool is_clear);
 
+  // Like get_init_tree, but passing in the type to use for the
+  // initializer.
+  tree
+  get_typed_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->do_get_init_tree(gogo, type_tree, is_clear); }
+
   // Return a tree for a make expression applied to this type.
   tree
   make_expression_tree(Translate_context* context, Expression_list* args,
@@ -858,7 +864,7 @@ 
   do_get_tree(Gogo*) = 0;
 
   virtual tree
-  do_init_tree(Gogo*, bool) = 0;
+  do_get_init_tree(Gogo*, tree, bool) = 0;
 
   virtual tree
   do_make_expression_tree(Translate_context*, Expression_list*,
@@ -911,10 +917,6 @@ 
   append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const
   { type->do_mangled_name(gogo, ret); }
 
-  // Store the type tree during construction.
-  void
-  set_incomplete_type_tree(tree);
-
   // Incorporate a string into a hash code.
   static unsigned int
   hash_string(const std::string&, unsigned int);
@@ -1232,7 +1234,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1308,7 +1310,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1380,7 +1382,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1436,7 +1438,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo* gogo, bool);
+  do_get_init_tree(Gogo* gogo, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1549,7 +1551,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1616,7 +1618,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1850,6 +1852,10 @@ 
   static Struct_type*
   do_import(Import*);
 
+  // Fill in the fields for a named struct type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1867,7 +1873,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -1939,6 +1945,10 @@ 
   static Array_type*
   do_import(Import*);
 
+  // Fill in the fields for a named slice type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
  protected:
   int
   do_traverse(Traverse* traverse);
@@ -1962,7 +1972,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   tree
   do_make_expression_tree(Translate_context*, Expression_list*,
@@ -2054,7 +2064,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   tree
   do_make_expression_tree(Translate_context*, Expression_list*,
@@ -2135,7 +2145,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo*, bool);
+  do_get_init_tree(Gogo*, tree, bool);
 
   tree
   do_make_expression_tree(Translate_context*, Expression_list*,
@@ -2226,6 +2236,10 @@ 
   static Interface_type*
   do_import(Import*);
 
+  // Fill in the fields for a named interface type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
  protected:
   int
   do_traverse(Traverse*);
@@ -2241,7 +2255,7 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo* gogo, bool);
+  do_get_init_tree(Gogo* gogo, tree, bool);
 
   void
   do_type_descriptor_decl(Gogo*, Named_type*, tree*);
@@ -2277,7 +2291,8 @@ 
       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), is_visible_(true), is_error_(false), seen_(false)
+      location_(location), named_tree_(NULL), is_visible_(true),
+      is_error_(false), seen_(false)
   { }
 
   // Return the associated Named_object.  This holds the actual name.
@@ -2444,8 +2459,8 @@ 
   do_get_tree(Gogo*);
 
   tree
-  do_init_tree(Gogo* gogo, bool is_clear)
-  { return this->type_->get_init_tree(gogo, is_clear); }
+  do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->type_->get_typed_init_tree(gogo, type_tree, is_clear); }
 
   tree
   do_make_expression_tree(Translate_context* context, Expression_list* args,
@@ -2492,6 +2507,9 @@ 
   Interface_method_tables* pointer_interface_method_tables_;
   // The location where this type was defined.
   source_location location_;
+  // 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_;
   // 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
@@ -2567,8 +2585,8 @@ 
   do_get_tree(Gogo* gogo);
 
   tree
-  do_init_tree(Gogo* gogo, bool is_clear)
-  { return this->base()->get_init_tree(gogo, is_clear); }
+  do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->base()->get_typed_init_tree(gogo, type_tree, is_clear); }
 
   tree
   do_make_expression_tree(Translate_context* context, Expression_list* args,