Rewrite conversion of named types to backend representation.
[gcc.git] / gcc / go / gofrontend / types.cc
index 0d17ab4773fb5c9338adc8d6b35706b7a6d31101..368ecae127a084c8457bcae6a5433a76f306e2f8 100644 (file)
@@ -835,8 +835,9 @@ Type::get_tree(Gogo* gogo)
     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 @@ Type::get_tree(Gogo* gogo)
       // 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 @@ Type::get_tree_without_hash(Gogo* gogo)
       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 @@ Type::make_builtin_struct_type(int nfields, ...)
   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 @@ Type::make_builtin_named_type(const char* name, Type* type)
 {
   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 @@ Call_multiple_result_type::do_get_tree(Gogo* gogo)
   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.
@@ -3583,7 +3601,8 @@ Struct_type::field_reference(Expression* struct_expr, const std::string& name,
                             source_location location) const
 {
   unsigned int depth;
-  return this->field_reference_depth(struct_expr, name, location, &depth);
+  return this->field_reference_depth(struct_expr, name, location, NULL,
+                                    &depth);
 }
 
 // Return an expression for a field, along with the depth at which it
@@ -3593,6 +3612,7 @@ Field_reference_expression*
 Struct_type::field_reference_depth(Expression* struct_expr,
                                   const std::string& name,
                                   source_location location,
+                                  Saw_named_type* saw,
                                   unsigned int* depth) const
 {
   const Struct_field_list* fields = this->fields_;
@@ -3628,13 +3648,41 @@ Struct_type::field_reference_depth(Expression* struct_expr,
       if (st == NULL)
        continue;
 
+      Saw_named_type* hold_saw = saw;
+      Saw_named_type saw_here;
+      Named_type* nt = pf->type()->named_type();
+      if (nt == NULL)
+       nt = pf->type()->deref()->named_type();
+      if (nt != NULL)
+       {
+         Saw_named_type* q;
+         for (q = saw; q != NULL; q = q->next)
+           {
+             if (q->nt == nt)
+               {
+                 // If this is an error, it will be reported
+                 // elsewhere.
+                 break;
+               }
+           }
+         if (q != NULL)
+           continue;
+         saw_here.next = saw;
+         saw_here.nt = nt;
+         saw = &saw_here;
+       }
+
       // Look for a reference using a NULL struct expression.  If we
       // find one, fill in the struct expression with a reference to
       // this field.
       unsigned int subdepth;
       Field_reference_expression* sub = st->field_reference_depth(NULL, name,
                                                                  location,
+                                                                 saw,
                                                                  &subdepth);
+
+      saw = hold_saw;
+
       if (sub == NULL)
        continue;
 
@@ -3752,7 +3800,6 @@ Struct_type::fill_in_tree(Gogo* gogo, tree type)
 {
   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)
@@ -3760,20 +3807,10 @@ Struct_type::fill_in_tree(Gogo* gogo, tree type)
       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);
@@ -3786,35 +3823,9 @@ Struct_type::fill_in_tree(Gogo* gogo, tree type)
 
   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
@@ -4257,6 +4268,10 @@ Array_type::verify_length()
 {
   if (this->length_ == NULL)
     return true;
+
+  Type_context context(Type::lookup_integer_type("int"), false);
+  this->length_->determine_type(&context);
+
   if (!this->length_->is_constant())
     {
       error_at(this->length_->location(), "array bound is not constant");
@@ -4264,30 +4279,23 @@ Array_type::verify_length()
     }
 
   mpz_t val;
-
-  Type* t = this->length_->type();
-  if (t->integer_type() != NULL)
+  mpz_init(val);
+  Type* vt;
+  if (!this->length_->integer_constant_value(true, val, &vt))
     {
-      Type* vt;
-      mpz_init(val);
-      if (!this->length_->integer_constant_value(true, val, &vt))
-       {
-         error_at(this->length_->location(),
-                  "array bound is not constant");
-         mpz_clear(val);
-         return false;
-       }
-    }
-  else if (t->float_type() != NULL)
-    {
-      Type* vt;
       mpfr_t fval;
       mpfr_init(fval);
       if (!this->length_->float_constant_value(fval, &vt))
        {
-         error_at(this->length_->location(),
-                  "array bound is not constant");
+         if (this->length_->type()->integer_type() != NULL
+             || this->length_->type()->float_type() != NULL)
+           error_at(this->length_->location(),
+                    "array bound is not constant");
+         else
+           error_at(this->length_->location(),
+                    "array bound is not numeric");
          mpfr_clear(fval);
+         mpz_clear(val);
          return false;
        }
       if (!mpfr_integer_p(fval))
@@ -4295,18 +4303,13 @@ Array_type::verify_length()
          error_at(this->length_->location(),
                   "array bound truncated to integer");
          mpfr_clear(fval);
+         mpz_clear(val);
          return false;
        }
       mpz_init(val);
       mpfr_get_z(val, fval, GMP_RNDN);
       mpfr_clear(fval);
     }
-  else
-    {
-      if (!t->is_error_type())
-       error_at(this->length_->location(), "array bound is not numeric");
-      return false;
-    }
 
   if (mpz_sgn(val) < 0)
     {
@@ -4442,37 +4445,67 @@ Array_type::do_get_tree(Gogo* gogo)
   if (this->length_ == NULL)
     {
       tree struct_type = gogo->slice_type_tree(void_type_node);
-      return this->fill_in_tree(gogo, struct_type);
+      return this->fill_in_slice_tree(gogo, struct_type);
     }
   else
     {
-      tree element_type_tree = this->element_type_->get_tree(gogo);
-      tree length_tree = this->get_length_tree(gogo);
-      if (element_type_tree == error_mark_node
-         || length_tree == error_mark_node)
-       return error_mark_node;
+      tree array_type = make_node(ARRAY_TYPE);
+      return this->fill_in_array_tree(gogo, array_type);
+    }
+}
 
-      length_tree = fold_convert(sizetype, length_tree);
+// Fill in the fields for an array type.  This is used for named array
+// types.
+
+tree
+Array_type::fill_in_array_tree(Gogo* gogo, tree array_type)
+{
+  gcc_assert(this->length_ != NULL);
 
-      // build_index_type takes the maximum index, which is one less
-      // than the length.
-      tree index_type = build_index_type(fold_build2(MINUS_EXPR, sizetype,
-                                                    length_tree,
-                                                    size_one_node));
+  tree element_type_tree = this->element_type_->get_tree(gogo);
+  tree length_tree = this->get_length_tree(gogo);
+  if (element_type_tree == error_mark_node
+      || length_tree == error_mark_node)
+    return error_mark_node;
 
-      return build_array_type(element_type_tree, index_type);
-    }
+  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
+  // the length.
+  tree index_type = build_index_type(fold_build2(MINUS_EXPR, sizetype,
+                                                length_tree,
+                                                size_one_node));
+
+  TREE_TYPE(array_type) = element_type_tree;
+  TYPE_DOMAIN(array_type) = index_type;
+  TYPE_ADDR_SPACE(array_type) = TYPE_ADDR_SPACE(element_type_tree);
+  layout_type(array_type);
+
+  if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree)
+      || TYPE_STRUCTURAL_EQUALITY_P(index_type))
+    SET_TYPE_STRUCTURAL_EQUALITY(array_type);
+  else if (TYPE_CANONICAL(element_type_tree) != element_type_tree
+          || TYPE_CANONICAL(index_type) != index_type)
+    TYPE_CANONICAL(array_type) =
+      build_array_type(TYPE_CANONICAL(element_type_tree),
+                      TYPE_CANONICAL(index_type));
+
+  return array_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)
+Array_type::fill_in_slice_tree(Gogo* gogo, tree struct_type)
 {
   gcc_assert(this->length_ == NULL);
 
   tree element_type_tree = this->element_type_->get_tree(gogo);
+  if (element_type_tree == error_mark_node)
+    return error_mark_node;
   tree field = TYPE_FIELDS(struct_type);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
   gcc_assert(POINTER_TYPE_P(TREE_TYPE(field))
@@ -5603,6 +5636,7 @@ Interface_type::finalize_methods()
 {
   if (this->methods_ == NULL)
     return;
+  std::vector<Named_type*> seen;
   bool is_recursive = false;
   size_t from = 0;
   size_t to = 0;
@@ -5630,6 +5664,7 @@ Interface_type::finalize_methods()
          ++from;
          continue;
        }
+
       Interface_type* it = p->type()->interface_type();
       if (it == NULL)
        {
@@ -5647,6 +5682,27 @@ Interface_type::finalize_methods()
          ++from;
          continue;
        }
+
+      Named_type* nt = p->type()->named_type();
+      if (nt != NULL)
+       {
+         std::vector<Named_type*>::const_iterator q;
+         for (q = seen.begin(); q != seen.end(); ++q)
+           {
+             if (*q == nt)
+               {
+                 error_at(p->location(), "inherited interface loop");
+                 break;
+               }
+           }
+         if (q != seen.end())
+           {
+             ++from;
+             continue;
+           }
+         seen.push_back(nt);
+       }
+
       const Typed_identifier_list* methods = it->methods();
       if (methods == NULL)
        {
@@ -6001,70 +6057,86 @@ tree
 Interface_type::do_get_tree(Gogo* gogo)
 {
   if (this->methods_ == NULL)
+    return Interface_type::empty_type_tree(gogo);
+  else
     {
-      // 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);
+      tree t = Interface_type::non_empty_type_tree(this->location_);
+      return this->fill_in_tree(gogo, t);
     }
-
-  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.
+// 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::fill_in_tree(Gogo* gogo, tree type)
+Interface_type::empty_type_tree(Gogo* gogo)
 {
-  gcc_assert(this->methods_ != NULL);
+  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);
+}
 
-  // 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.
+// 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 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);
+  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");
-  tree field = build_decl(this->location_, FIELD_DECL, name_tree,
-                         ptr_type_node);
-  DECL_CONTEXT(field) = type;
+  field = build_decl(location, FIELD_DECL, name_tree, ptr_type_node);
+  DECL_CONTEXT(field) = ret;
   *pp = field;
 
-  TYPE_FIELDS(type) = field_trees;
+  TYPE_FIELDS(ret) = field_trees;
 
-  layout_type(type);
+  layout_type(ret);
+
+  return ret;
+}
+
+// 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");
+  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)
@@ -6086,7 +6158,10 @@ Interface_type::fill_in_tree(Gogo* gogo, tree type)
 
   // 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;
 }
@@ -6803,7 +6878,7 @@ Named_type::named_type_has_hidden_fields(std::string* reason) const
 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)
   { }
@@ -6819,7 +6894,7 @@ class Find_type_use : public Traverse
 
  private:
   // The type we are looking for.
-  Type* find_type_;
+  Named_type* find_type_;
   // Whether we found the type.
   bool found_;
 };
@@ -6829,11 +6904,12 @@ class Find_type_use : public Traverse
 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.
@@ -6867,6 +6943,42 @@ Find_type_use::type(Type* type)
       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;
 }
 
@@ -6922,26 +7034,6 @@ Named_type::do_verify()
        return false;
     }
 
-  // If this is a struct, then if any of the fields of the struct
-  // themselves have 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);
-       }
-    }
-
   return true;
 }
 
@@ -6991,21 +7083,109 @@ Named_type::do_hash_for_method(Gogo* gogo) const
   return ret;
 }
 
-// Get a tree for a named type.
+// 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.
 
-tree
-Named_type::do_get_tree(Gogo* gogo)
+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:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      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_)
-    return error_mark_node;
+    this->named_tree_ = error_mark_node;
+
+  if (this->named_tree_ != NULL_TREE)
+    return;
 
-  // Go permits types to refer to themselves in various ways.  Break
-  // the recursion here.
+  // 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 (this->type_->forwarded()->classification())
+  switch (base->classification())
     {
     case TYPE_ERROR:
-      return error_mark_node;
+      this->is_error_ = true;
+      this->named_tree_ = error_mark_node;
+      return;
 
     case TYPE_VOID:
     case TYPE_BOOLEAN:
@@ -7014,159 +7194,194 @@ Named_type::do_get_tree(Gogo* gogo)
     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 = Type::get_named_type_tree(gogo, this->type_);
+      // These are simple basic types, we can just create them
+      // directly.
+      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)
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      // All maps and channels have the same type in GENERIC.
+      t = Type::get_named_type_tree(gogo, base);
+      if (t == error_mark_node)
        {
-         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->is_error_ = true;
+         this->named_tree_ = error_mark_node;
+         return;
        }
-      ++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);
       break;
 
+    case TYPE_FUNCTION:
     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);
+      t = build_variant_type_copy(ptr_type_node);
       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;
-       }
       break;
 
     case TYPE_ARRAY:
-      if (!this->is_open_array_type())
-       t = Type::get_named_type_tree(gogo, this->type_);
+      if (base->is_open_array_type())
+       t = gogo->slice_type_tree(void_type_node);
       else
-       {
-         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);
-       }
-      if (t == error_mark_node)
-       return error_mark_node;
-      t = build_variant_type_copy(t);
+       t = make_node(ARRAY_TYPE);
       break;
 
     case TYPE_INTERFACE:
-      if (this->type_->interface_type()->is_empty())
+      if (base->interface_type()->is_empty())
        {
-         t = Type::get_named_type_tree(gogo, this->type_);
-         if (t == error_mark_node)
-           return error_mark_node;
+         t = Interface_type::empty_type_tree(gogo);
          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;
-           }
+         source_location loc = base->interface_type()->location();
+         t = Interface_type::non_empty_type_tree(loc);
        }
       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.
@@ -7488,7 +7703,13 @@ Type::add_interface_methods_for_type(const Type* type,
        ++pm)
     {
       Function_type* fntype = pm->type()->function_type();
-      gcc_assert(fntype != NULL && !fntype->is_method());
+      if (fntype == NULL)
+       {
+         // This is an error, but it should be reported elsewhere
+         // when we look at the methods for IT.
+         continue;
+       }
+      gcc_assert(!fntype->is_method());
       fntype = fntype->copy_with_receiver(const_cast<Type*>(type));
       Method* m = new Interface_method(pm->name(), pm->location(), fntype,
                                       field_indexes, depth);
@@ -7758,6 +7979,8 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
     {
       expr = Expression::make_unary(OPERATOR_MULT, expr, location);
       type = type->points_to();
+      if (type->deref()->is_error_type())
+       return Expression::make_error(location);
       nt = type->points_to()->named_type();
       st = type->points_to()->struct_type();
       it = type->points_to()->interface_type();