diff mbox

Go patch committed: Use backend interface for named types

Message ID mcrei4e1nfy.fsf@coign.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor May 4, 2011, 3:43 p.m. UTC
This patch to the Go frontend uses the backend interface for named
types, and also array type.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


2011-05-04  Ian Lance Taylor  <iant@google.com>

	* go-gcc.cc (Gcc_backend::struct_type): Call fill_in_struct.
	(Gcc_backend::fill_in_struct): New function.
	(Gcc_backend::array_type): Implement.
	(Gcc_backend::fill_in_array): New function.
	(Gcc_backend::placeholder_pointer_type): New function.
	(Gcc_backend::set_placeholder_pointer_type): New function.
	(Gcc_backend::set_placeholder_function_type): New function.
	(Gcc_backend::placeholder_struct_type): New function.
	(Gcc_backend::set_placeholder_struct_type): New function.
	(Gcc_backend::placeholder_array_type): New function.
	(Gcc_backend::set_placeholder_array_type): New function.
	(Gcc_backend::named_type): New function.
	(Gcc_backend::circular_pointer_type): New function.
	(Gcc_backend::is_circular_pointer_type): New function.
diff mbox

Patch

Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 173004)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -161,8 +161,38 @@  class Gcc_backend : public Backend
   struct_type(const std::vector<Btyped_identifier>&);
 
   Btype*
-  array_type(const Btype* /* element_type */, const Bexpression* /* length */)
-  { gcc_unreachable(); }
+  array_type(Btype*, Bexpression*);
+
+  Btype*
+  placeholder_pointer_type(const std::string&, source_location, bool);
+
+  bool
+  set_placeholder_pointer_type(Btype*, Btype*);
+
+  bool
+  set_placeholder_function_type(Btype*, Btype*);
+
+  Btype*
+  placeholder_struct_type(const std::string&, source_location);
+
+  bool
+  set_placeholder_struct_type(Btype* placeholder,
+			      const std::vector<Btyped_identifier>&);
+
+  Btype*
+  placeholder_array_type(const std::string&, source_location);
+
+  bool
+  set_placeholder_array_type(Btype*, Btype*, Bexpression*);
+
+  Btype*
+  named_type(const std::string&, Btype*, source_location);
+
+  Btype*
+  circular_pointer_type(Btype*, bool);
+
+  bool
+  is_circular_pointer_type(Btype*);
 
   // Statements.
 
@@ -270,6 +300,12 @@  class Gcc_backend : public Backend
   Btype*
   make_type(tree t)
   { return new Btype(t); }
+
+  Btype*
+  fill_in_struct(Btype*, const std::vector<Btyped_identifier>&);
+
+  Btype*
+  fill_in_array(Btype*, Btype*, Bexpression*);
 };
 
 // A helper function.
@@ -453,7 +489,16 @@  Gcc_backend::function_type(const Btyped_
 Btype*
 Gcc_backend::struct_type(const std::vector<Btyped_identifier>& fields)
 {
-  tree ret = make_node(RECORD_TYPE);
+  return this->fill_in_struct(this->make_type(make_node(RECORD_TYPE)), fields);
+}
+
+// Fill in the fields of a struct type.
+
+Btype*
+Gcc_backend::fill_in_struct(Btype* fill,
+			    const std::vector<Btyped_identifier>& fields)
+{
+  tree fill_tree = fill->get_tree();
   tree field_trees = NULL_TREE;
   tree* pp = &field_trees;
   for (std::vector<Btyped_identifier>::const_iterator p = fields.begin();
@@ -465,15 +510,192 @@  Gcc_backend::struct_type(const std::vect
       if (type_tree == error_mark_node)
 	return this->error_type();
       tree field = build_decl(p->location, FIELD_DECL, name_tree, type_tree);
-      DECL_CONTEXT(field) = ret;
+      DECL_CONTEXT(field) = fill_tree;
       *pp = field;
       pp = &DECL_CHAIN(field);
     }
-  TYPE_FIELDS(ret) = field_trees;
-  layout_type(ret);
+  TYPE_FIELDS(fill_tree) = field_trees;
+  layout_type(fill_tree);
+  return fill;
+}
+
+// Make an array type.
+
+Btype*
+Gcc_backend::array_type(Btype* element_btype, Bexpression* length)
+{
+  return this->fill_in_array(this->make_type(make_node(ARRAY_TYPE)),
+			     element_btype, length);
+}
+
+// Fill in an array type.
+
+Btype*
+Gcc_backend::fill_in_array(Btype* fill, Btype* element_type,
+			   Bexpression* length)
+{
+  tree element_type_tree = element_type->get_tree();
+  tree length_tree = length->get_tree();
+  if (element_type_tree == error_mark_node || length_tree == error_mark_node)
+    return this->error_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_tree = build_index_type(fold_build2(MINUS_EXPR, sizetype,
+						      length_tree,
+						      size_one_node));
+
+  tree fill_tree = fill->get_tree();
+  TREE_TYPE(fill_tree) = element_type_tree;
+  TYPE_DOMAIN(fill_tree) = index_type_tree;
+  TYPE_ADDR_SPACE(fill_tree) = TYPE_ADDR_SPACE(element_type_tree);
+  layout_type(fill_tree);
+
+  if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree))
+    SET_TYPE_STRUCTURAL_EQUALITY(fill_tree);
+  else if (TYPE_CANONICAL(element_type_tree) != element_type_tree
+	   || TYPE_CANONICAL(index_type_tree) != index_type_tree)
+    TYPE_CANONICAL(fill_tree) =
+      build_array_type(TYPE_CANONICAL(element_type_tree),
+		       TYPE_CANONICAL(index_type_tree));
+
+  return fill;
+}
+
+// Create a placeholder for a pointer type.
+
+Btype*
+Gcc_backend::placeholder_pointer_type(const std::string& name,
+				      source_location location, bool)
+{
+  tree ret = build_variant_type_copy(ptr_type_node);
+  tree decl = build_decl(location, TYPE_DECL,
+			 get_identifier_from_string(name),
+			 ret);
+  TYPE_NAME(ret) = decl;
   return this->make_type(ret);
 }
 
+// Set the real target type for a placeholder pointer type.
+
+bool
+Gcc_backend::set_placeholder_pointer_type(Btype* placeholder,
+					  Btype* to_type)
+{
+  tree pt = placeholder->get_tree();
+  if (pt == error_mark_node)
+    return false;
+  gcc_assert(TREE_CODE(pt) == POINTER_TYPE);
+  tree tt = to_type->get_tree();
+  if (tt == error_mark_node)
+    {
+      TREE_TYPE(pt) = tt;
+      return false;
+    }
+  gcc_assert(TREE_CODE(tt) == POINTER_TYPE);
+  TREE_TYPE(pt) = TREE_TYPE(tt);
+  return true;
+}
+
+// Set the real values for a placeholder function type.
+
+bool
+Gcc_backend::set_placeholder_function_type(Btype* placeholder, Btype* ft)
+{
+  return this->set_placeholder_pointer_type(placeholder, ft);
+}
+
+// Create a placeholder for a struct type.
+
+Btype*
+Gcc_backend::placeholder_struct_type(const std::string& name,
+				     source_location location)
+{
+  tree ret = make_node(RECORD_TYPE);
+  tree decl = build_decl(location, TYPE_DECL,
+			 get_identifier_from_string(name),
+			 ret);
+  TYPE_NAME(ret) = decl;
+  return this->make_type(ret);
+}
+
+// Fill in the fields of a placeholder struct type.
+
+bool
+Gcc_backend::set_placeholder_struct_type(
+    Btype* placeholder,
+    const std::vector<Btyped_identifier>& fields)
+{
+  tree t = placeholder->get_tree();
+  gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE);
+  Btype* r = this->fill_in_struct(placeholder, fields);
+  return r->get_tree() != error_mark_node;
+}
+
+// Create a placeholder for an array type.
+
+Btype*
+Gcc_backend::placeholder_array_type(const std::string& name,
+				    source_location location)
+{
+  tree ret = make_node(ARRAY_TYPE);
+  tree decl = build_decl(location, TYPE_DECL,
+			 get_identifier_from_string(name),
+			 ret);
+  TYPE_NAME(ret) = decl;
+  return this->make_type(ret);
+}
+
+// Fill in the fields of a placeholder array type.
+
+bool
+Gcc_backend::set_placeholder_array_type(Btype* placeholder,
+					Btype* element_btype,
+					Bexpression* length)
+{
+  tree t = placeholder->get_tree();
+  gcc_assert(TREE_CODE(t) == ARRAY_TYPE && TREE_TYPE(t) == NULL_TREE);
+  Btype* r = this->fill_in_array(placeholder, element_btype, length);
+  return r->get_tree() != error_mark_node;
+}
+
+// Return a named version of a type.
+
+Btype*
+Gcc_backend::named_type(const std::string& name, Btype* btype,
+			source_location location)
+{
+  tree type = btype->get_tree();
+  if (type == error_mark_node)
+    return this->error_type();
+  type = build_variant_type_copy(type);
+  tree decl = build_decl(location, TYPE_DECL,
+			 get_identifier_from_string(name),
+			 type);
+  TYPE_NAME(type) = decl;
+  return this->make_type(type);
+}
+
+// Return a pointer type used as a marker for a circular type.
+
+Btype*
+Gcc_backend::circular_pointer_type(Btype*, bool)
+{
+  return this->make_type(ptr_type_node);
+}
+
+// Return whether we might be looking at a circular type.
+
+bool
+Gcc_backend::is_circular_pointer_type(Btype* btype)
+{
+  return btype->get_tree() == ptr_type_node;
+}
+
 // An expression as a statement.
 
 Bstatement*
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 172932)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -42,6 +42,8 @@  class Function;
 class Translate_context;
 class Export;
 class Import;
+class Btype;
+class Bexpression;
 
 // Type codes used in type descriptors.  These must match the values
 // in libgo/runtime/go-type.h.  They also match the values in the gc
@@ -973,10 +975,11 @@  class Type
   static unsigned int
   hash_string(const std::string&, unsigned int);
 
-  // Return a tree for the underlying type of a named type.
-  static tree
-  get_named_type_tree(Gogo* gogo, Type* base_type)
-  { return base_type->get_tree_without_hash(gogo); }
+  // Return the backend representation for the underlying type of a
+  // named type.
+  static Btype*
+  get_named_base_btype(Gogo* gogo, Type* base_type)
+  { return base_type->get_btype_without_hash(gogo); }
 
  private:
   // Convert to the desired type classification, or return NULL.  This
@@ -1100,6 +1103,11 @@  class Type
   tree
   get_tree_without_hash(Gogo*);
 
+  // Get the backend representation for a type without looking in the
+  // hash table for identical types.
+  Btype*
+  get_btype_without_hash(Gogo*);
+
   // A mapping from Type to tree, used to ensure that the GIMPLE
   // representation of identical types is identical.
   typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
@@ -1952,10 +1960,6 @@  class Struct_type : public Type
   static Struct_type*
   do_import(Import*);
 
-  // Fill in the fields for a named struct type.
-  tree
-  fill_in_tree(Gogo*, tree);
-
   static Type*
   make_struct_type_descriptor_type();
 
@@ -2056,9 +2060,13 @@  class Array_type : public Type
   static Array_type*
   do_import(Import*);
 
-  // Fill in the fields for a named array type.
-  tree
-  fill_in_array_tree(Gogo*, tree);
+  // Return the backend representation of the element type.
+  Btype*
+  get_backend_element(Gogo*);
+
+  // Return the backend representation of the length.
+  Bexpression*
+  get_backend_length(Gogo*);
 
   // Fill in the fields for a named slice type.
   tree
@@ -2430,7 +2438,7 @@  class Named_type : public Type
       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), dependencies_(),
+      location_(location), named_btype_(NULL), dependencies_(),
       is_visible_(true), is_error_(false), is_converted_(false),
       is_circular_(false), seen_(0)
   { }
@@ -2676,9 +2684,10 @@  class Named_type : public Type
   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_;
+  // The backend representation of this type during backend
+  // conversion.  This is used to avoid endless recursion when a named
+  // type refers to itself.
+  Btype* named_btype_;
   // A list of types which must be converted to the backend
   // representation before this type can be converted.  This is for
   // cases like
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 172932)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -108,7 +108,93 @@  class Backend
 
   // Get an array type.
   virtual Btype*
-  array_type(const Btype* element_type, const Bexpression* length) = 0;
+  array_type(Btype* element_type, Bexpression* length) = 0;
+
+  // Create a placeholder pointer type.  This is used for a named
+  // pointer type, since in Go a pointer type may refer to itself.
+  // NAME is the name of the type, and the location is where the named
+  // type is defined.  FOR_FUNCTION is true if this is for a Go
+  // function type, which corresponds to a C/C++ pointer to function
+  // type.  The return value will later be passed as the first
+  // parameter to set_placeholder_pointer_type or
+  // set_placeholder_function_type.
+  virtual Btype*
+  placeholder_pointer_type(const std::string& name, source_location,
+			   bool for_function) = 0;
+
+  // Fill in a placeholder pointer type as a pointer.  This takes a
+  // type returned by placeholder_pointer_type and arranges for it to
+  // point to to_type.  Returns true on success, false on failure.
+  virtual bool
+  set_placeholder_pointer_type(Btype* placeholder, Btype* to_type) = 0;
+
+  // Fill in a placeholder pointer type as a function.  This takes a
+  // type returned by placeholder_pointer_type and arranges for it to
+  // become a real Go function type (which corresponds to a C/C++
+  // pointer to function type).  FT will be something returned by the
+  // function_type method.  Returns true on success, false on failure.
+  virtual bool
+  set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0;
+
+  // Create a placeholder struct type.  This is used for a named
+  // struct type, as with placeholder_pointer_type.
+  virtual Btype*
+  placeholder_struct_type(const std::string& name, source_location) = 0;
+
+  // Fill in a placeholder struct type.  This takes a type returned by
+  // placeholder_struct_type and arranges for it to become a real
+  // struct type.  The parameter is as for struct_type.  Returns true
+  // on success, false on failure.
+  virtual bool
+  set_placeholder_struct_type(Btype* placeholder,
+			      const std::vector<Btyped_identifier>& fields)
+  			= 0;
+
+  // Create a placeholder array type.  This is used for a named array
+  // type, as with placeholder_pointer_type, to handle cases like
+  // type A []*A.
+  virtual Btype*
+  placeholder_array_type(const std::string& name, source_location) = 0;
+
+  // Fill in a placeholder array type.  This takes a type returned by
+  // placeholder_array_type and arranges for it to become a real array
+  // type.  The parameters are as for array_type.  Returns true on
+  // success, false on failure.
+  virtual bool
+  set_placeholder_array_type(Btype* placeholder, Btype* element_type,
+			     Bexpression* length) = 0;
+
+  // Return a named version of a type.  The location is the location
+  // of the type definition.  This will not be called for a type
+  // created via placeholder_pointer_type, placeholder_struct_type, or
+  // placeholder_array_type..  (It may be called for a pointer,
+  // struct, or array type in a case like "type P *byte; type Q P".)
+  virtual Btype*
+  named_type(const std::string& name, Btype*, source_location) = 0;
+
+  // Create a marker for a circular pointer type.  Go pointer and
+  // function types can refer to themselves in ways that are not
+  // permitted in C/C++.  When a circular type is found, this function
+  // is called for the circular reference.  This permits the backend
+  // to decide how to handle such a type.  PLACEHOLDER is the
+  // placeholder type which has already been created; if the backend
+  // is prepared to handle a circular pointer type, it may simply
+  // return PLACEHOLDER.  FOR_FUNCTION is true if this is for a
+  // function type.
+  //
+  // For "type P *P" the sequence of calls will be
+  //   bt1 = placeholder_pointer_type();
+  //   bt2 = circular_pointer_type(bt1, false);
+  //   set_placeholder_pointer_type(bt1, bt2);
+  virtual Btype*
+  circular_pointer_type(Btype* placeholder, bool for_function) = 0;
+
+  // Return whether the argument could be a special type created by
+  // circular_pointer_type.  This is used to introduce explicit type
+  // conversions where needed.  If circular_pointer_type returns its
+  // PLACEHOLDER parameter, this may safely always return false.
+  virtual bool
+  is_circular_pointer_type(Btype*) = 0;
 
   // Statements.
 
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 173004)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -896,10 +896,11 @@  Type::get_tree_without_hash(Gogo* gogo)
       tree t = this->do_get_tree(gogo);
 
       // For a recursive function or pointer type, we will temporarily
-      // return ptr_type_node during the recursion.  We don't want to
-      // record that for a forwarding type, as it may confuse us
-      // later.
-      if (t == ptr_type_node && this->forward_declaration_type() != NULL)
+      // return a circular pointer type during the recursion.  We
+      // don't want to record that for a forwarding type, as it may
+      // confuse us later.
+      if (this->forward_declaration_type() != NULL
+	  && gogo->backend()->is_circular_pointer_type(tree_to_type(t)))
 	return t;
 
       if (gogo == NULL || !gogo->named_types_are_converted())
@@ -912,6 +913,16 @@  Type::get_tree_without_hash(Gogo* gogo)
   return this->tree_;
 }
 
+// Return the backend representation for a type without looking in the
+// hash table for identical types.  This is used for named types,
+// since a named type is never identical to any other type.
+
+Btype*
+Type::get_btype_without_hash(Gogo* gogo)
+{
+  return tree_to_type(this->get_tree_without_hash(gogo));
+}
+
 // Return a tree representing a zero initialization for this type.
 
 tree
@@ -3748,58 +3759,36 @@  Struct_type::method_function(const std::
   return Type::method_function(this->all_methods_, name, is_ambiguous);
 }
 
-// Get the tree for a struct type.
-
-tree
-Struct_type::do_get_tree(Gogo* gogo)
+// Convert struct fields to the backend representation.  This is not
+// declared in types.h so that types.h doesn't have to #include
+// backend.h.
+
+static void
+get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
+			  std::vector<Backend::Btyped_identifier>* bfields)
 {
-  std::vector<Backend::Btyped_identifier> fields;
-  fields.resize(this->fields_->size());
+  bfields->resize(fields->size());
   size_t i = 0;
-  for (Struct_field_list::const_iterator p = this->fields_->begin();
-       p != this->fields_->end();
+  for (Struct_field_list::const_iterator p = fields->begin();
+       p != fields->end();
        ++p, ++i)
     {
-      fields[i].name = Gogo::unpack_hidden_name(p->field_name());
-      fields[i].btype = tree_to_type(p->type()->get_tree(gogo));
-      fields[i].location = p->location();
+      (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name());
+      (*bfields)[i].btype = tree_to_type(p->type()->get_tree(gogo));
+      (*bfields)[i].location = p->location();
     }
-  go_assert(i == this->fields_->size());
-  Btype* btype = gogo->backend()->struct_type(fields);
-  return type_to_tree(btype);
+  go_assert(i == fields->size());
 }
 
-// Fill in the fields for a struct type.
+// Get the tree for a struct type.
 
 tree
-Struct_type::fill_in_tree(Gogo* gogo, tree type)
+Struct_type::do_get_tree(Gogo* gogo)
 {
-  tree field_trees = NULL_TREE;
-  tree* pp = &field_trees;
-  for (Struct_field_list::const_iterator p = this->fields_->begin();
-       p != this->fields_->end();
-       ++p)
-    {
-      std::string name = Gogo::unpack_hidden_name(p->field_name());
-      tree name_tree = get_identifier_with_length(name.data(), name.length());
-
-      tree field_type_tree = p->type()->get_tree(gogo);
-      if (field_type_tree == error_mark_node)
-	return error_mark_node;
-      go_assert(TYPE_SIZE(field_type_tree) != NULL_TREE);
-
-      tree field = build_decl(p->location(), FIELD_DECL, name_tree,
-			      field_type_tree);
-      DECL_CONTEXT(field) = type;
-      *pp = field;
-      pp = &DECL_CHAIN(field);
-    }
-
-  TYPE_FIELDS(type) = field_trees;
-
-  layout_type(type);
-
-  return type;
+  std::vector<Backend::Btyped_identifier> bfields;
+  get_backend_struct_fields(gogo, this->fields_, &bfields);
+  Btype* btype = gogo->backend()->struct_type(bfields);
+  return type_to_tree(btype);
 }
 
 // Initialize struct fields.
@@ -4425,50 +4414,26 @@  Array_type::do_get_tree(Gogo* gogo)
     }
   else
     {
-      tree array_type = make_node(ARRAY_TYPE);
-      return this->fill_in_array_tree(gogo, array_type);
+      Btype* element = this->get_backend_element(gogo);
+      Bexpression* len = this->get_backend_length(gogo);
+      Btype* ret = gogo->backend()->array_type(element, len);
+      return type_to_tree(ret);
     }
 }
 
-// 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)
+// Return the backend representation of the element type.
+Btype*
+Array_type::get_backend_element(Gogo* gogo)
 {
-  go_assert(this->length_ != NULL);
-
-  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;
-
-  go_assert(TYPE_SIZE(element_type_tree) != NULL_TREE);
-
-  length_tree = fold_convert(sizetype, length_tree);
+  return tree_to_type(this->element_type_->get_tree(gogo));
+}
 
-  // 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 the backend representation of the length.
 
-  return array_type;
+Bexpression*
+Array_type::get_backend_length(Gogo* gogo)
+{
+  return tree_to_expr(this->get_length_tree(gogo));
 }
 
 // Fill in the fields for a slice type.  This is used for named slice
@@ -7073,7 +7038,7 @@  Named_type::convert(Gogo* gogo)
     (*p)->convert(gogo);
 
   // Complete this type.
-  tree t = this->named_tree_;
+  Btype* bt = this->named_btype_;
   Type* base = this->type_->base();
   switch (base->classification())
     {
@@ -7092,21 +7057,37 @@  Named_type::convert(Gogo* gogo)
 
     case TYPE_FUNCTION:
     case TYPE_POINTER:
-      // The size of these types is already correct.
+      // The size of these types is already correct.  We don't worry
+      // about filling them in until later, when we also track
+      // circular references.
       break;
 
     case TYPE_STRUCT:
-      t = base->struct_type()->fill_in_tree(gogo, t);
+      {
+	std::vector<Backend::Btyped_identifier> bfields;
+	get_backend_struct_fields(gogo, base->struct_type()->fields(),
+				  &bfields);
+	if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
+	  bt = gogo->backend()->error_type();
+      }
       break;
 
     case TYPE_ARRAY:
       if (!base->is_open_array_type())
-	t = base->array_type()->fill_in_array_tree(gogo, t);
+	{
+	  Btype* bet = base->array_type()->get_backend_element(gogo);
+	  Bexpression* blen = base->array_type()->get_backend_length(gogo);
+	  if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen))
+	    bt = gogo->backend()->error_type();
+	}
       break;
 
     case TYPE_INTERFACE:
       if (!base->interface_type()->is_empty())
-	t = base->interface_type()->fill_in_tree(gogo, t);
+	{
+	  tree t = type_to_tree(bt);
+	  bt = tree_to_type(base->interface_type()->fill_in_tree(gogo, t));
+	}
       break;
 
     case TYPE_ERROR:
@@ -7120,13 +7101,7 @@  Named_type::convert(Gogo* gogo)
       go_unreachable();
     }
 
-  this->named_tree_ = t;
-
-  if (t == error_mark_node)
-    this->is_error_ = true;
-  else
-    go_assert(TYPE_SIZE(t) != NULL_TREE);
-
+  this->named_btype_ = bt;
   this->is_converted_ = true;
 }
 
@@ -7137,9 +7112,9 @@  void
 Named_type::create_placeholder(Gogo* gogo)
 {
   if (this->is_error_)
-    this->named_tree_ = error_mark_node;
+    this->named_btype_ = gogo->backend()->error_type();
 
-  if (this->named_tree_ != NULL_TREE)
+  if (this->named_btype_ != NULL)
     return;
 
   // Create the structure for this type.  Note that because we call
@@ -7147,12 +7122,13 @@  Named_type::create_placeholder(Gogo* gog
   // as another named type.  Instead both named types will point to
   // different base representations.
   Type* base = this->type_->base();
-  tree t;
+  Btype* bt;
+  bool set_name = true;
   switch (base->classification())
     {
     case TYPE_ERROR:
       this->is_error_ = true;
-      this->named_tree_ = error_mark_node;
+      this->named_btype_ = gogo->backend()->error_type();
       return;
 
     case TYPE_VOID:
@@ -7164,55 +7140,50 @@  Named_type::create_placeholder(Gogo* gog
     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);
+      bt = Type::get_named_base_btype(gogo, base);
       break;
 
     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)
-	{
-	  this->is_error_ = true;
-	  this->named_tree_ = error_mark_node;
-	  return;
-	}
-      t = build_variant_type_copy(t);
+      // All maps and channels have the same backend representation.
+      bt = Type::get_named_base_btype(gogo, base);
       break;
 
     case TYPE_FUNCTION:
     case TYPE_POINTER:
-      t = build_variant_type_copy(ptr_type_node);
+      {
+	bool for_function = base->classification() == TYPE_FUNCTION;
+	bt = gogo->backend()->placeholder_pointer_type(this->name(),
+						       this->location_,
+						       for_function);
+	set_name = false;
+      }
       break;
 
     case TYPE_STRUCT:
-      t = make_node(RECORD_TYPE);
+      bt = gogo->backend()->placeholder_struct_type(this->name(),
+						    this->location_);
+      set_name = false;
       break;
 
     case TYPE_ARRAY:
       if (base->is_open_array_type())
-	t = gogo->slice_type_tree(void_type_node);
+	bt = tree_to_type(gogo->slice_type_tree(void_type_node));
       else
-	t = make_node(ARRAY_TYPE);
+	{
+	  bt = gogo->backend()->placeholder_array_type(this->name(),
+						       this->location_);
+	  set_name = false;
+	}
       break;
 
     case TYPE_INTERFACE:
       if (base->interface_type()->is_empty())
-	{
-	  t = Interface_type::empty_type_tree(gogo);
-	  t = build_variant_type_copy(t);
-	}
+	bt = tree_to_type(Interface_type::empty_type_tree(gogo));
       else
 	{
 	  source_location loc = base->interface_type()->location();
-	  t = Interface_type::non_empty_type_tree(loc);
+	  bt = tree_to_type(Interface_type::non_empty_type_tree(loc));
 	}
       break;
 
@@ -7224,13 +7195,10 @@  Named_type::create_placeholder(Gogo* gog
       go_unreachable();
     }
 
-  // Create the named type.
+  if (set_name)
+    bt = gogo->backend()->named_type(this->name(), bt, this->location_);
 
-  tree id = this->named_object_->get_id(gogo);
-  tree decl = build_decl(this->location_, TYPE_DECL, id, t);
-  TYPE_NAME(t) = decl;
-
-  this->named_tree_ = t;
+  this->named_btype_ = bt;
 }
 
 // Get a tree for a named type.
@@ -7241,24 +7209,22 @@  Named_type::do_get_tree(Gogo* gogo)
   if (this->is_error_)
     return error_mark_node;
 
-  tree t = this->named_tree_;
+  Btype* bt = this->named_btype_;
 
-  // 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;
+  if (!gogo->named_types_are_converted())
+    {
+      // We have not completed converting named types.  NAMED_BTYPE_
+      // is a placeholder and we shouldn't do anything further.
+      if (bt != NULL)
+	return type_to_tree(bt);
 
       // 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_;
-      go_assert(t != NULL_TREE);
-      return t;
+      bt = this->named_btype_;
+      go_assert(bt != NULL);
+      return type_to_tree(bt);
     }
 
   // We are not converting types.  This should only be called if the
@@ -7269,11 +7235,11 @@  Named_type::do_get_tree(Gogo* gogo)
       return error_mark_node;
     }
 
-  go_assert(t != NULL_TREE && TYPE_SIZE(t) != NULL_TREE);
+  go_assert(bt != NULL);
 
   // Complete the tree.
   Type* base = this->type_->base();
-  tree t1;
+  Btype* bt1;
   switch (base->classification())
     {
     case TYPE_ERROR:
@@ -7290,7 +7256,7 @@  Named_type::do_get_tree(Gogo* gogo)
     case TYPE_CHANNEL:
     case TYPE_STRUCT:
     case TYPE_INTERFACE:
-      return t;
+      return type_to_tree(bt);
 
     case TYPE_FUNCTION:
       // Don't build a circular data structure.  GENERIC can't handle
@@ -7298,19 +7264,17 @@  Named_type::do_get_tree(Gogo* gogo)
       if (this->seen_ > 0)
 	{
 	  this->is_circular_ = true;
-	  return ptr_type_node;
+	  bt1 = gogo->backend()->circular_pointer_type(bt, true);
+	  return type_to_tree(bt1);
 	}
       ++this->seen_;
-      t1 = Type::get_named_type_tree(gogo, base);
+      bt1 = Type::get_named_base_btype(gogo, base);
       --this->seen_;
-      if (t1 == error_mark_node)
-	return error_mark_node;
       if (this->is_circular_)
-	t1 = ptr_type_node;
-      go_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE);
-      go_assert(TREE_CODE(t1) == POINTER_TYPE);
-      TREE_TYPE(t) = TREE_TYPE(t1);
-      return t;
+	bt1 = gogo->backend()->circular_pointer_type(bt, true);
+      if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1))
+	bt = gogo->backend()->error_type();
+      return type_to_tree(bt);
 
     case TYPE_POINTER:
       // Don't build a circular data structure. GENERIC can't handle
@@ -7318,33 +7282,33 @@  Named_type::do_get_tree(Gogo* gogo)
       if (this->seen_ > 0)
 	{
 	  this->is_circular_ = true;
-	  return ptr_type_node;
+	  bt1 = gogo->backend()->circular_pointer_type(bt, false);
+	  return type_to_tree(bt1);
 	}
       ++this->seen_;
-      t1 = Type::get_named_type_tree(gogo, base);
+      bt1 = Type::get_named_base_btype(gogo, base);
       --this->seen_;
-      if (t1 == error_mark_node)
-	return error_mark_node;
       if (this->is_circular_)
-	t1 = ptr_type_node;
-      go_assert(t != NULL_TREE && TREE_CODE(t) == POINTER_TYPE);
-      go_assert(TREE_CODE(t1) == POINTER_TYPE);
-      TREE_TYPE(t) = TREE_TYPE(t1);
-      return t;
+	bt1 = gogo->backend()->circular_pointer_type(bt, false);
+      if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1))
+	bt = gogo->backend()->error_type();
+      return type_to_tree(bt);
 
     case TYPE_ARRAY:
       if (base->is_open_array_type())
 	{
 	  if (this->seen_ > 0)
-	    return t;
+	    return type_to_tree(bt);
 	  else
 	    {
 	      ++this->seen_;
-	      t = base->array_type()->fill_in_slice_tree(gogo, t);
+	      tree t = base->array_type()->fill_in_slice_tree(gogo,
+							      type_to_tree(bt));
+	      bt = tree_to_type(t);
 	      --this->seen_;
 	    }
 	}
-      return t;
+      return type_to_tree(bt);
 
     default:
     case TYPE_SINK:
@@ -8467,7 +8431,7 @@  tree
 Forward_declaration_type::do_get_tree(Gogo* gogo)
 {
   if (this->is_defined())
-    return Type::get_named_type_tree(gogo, this->real_type());
+    return type_to_tree(Type::get_named_base_btype(gogo, this->real_type()));
 
   if (this->warned_)
     return error_mark_node;