diff mbox

Go patch committed: Use backend interface for global decls

Message ID mcreh0k92v6.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor April 26, 2014, 3:38 a.m. UTC
This patch from Chris Manghane changes the Go frontend to use the
backend interface for global declarations.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


2014-04-25  Chris Manghane  <cmang@google.com>

	* go-gcc.cc: Include "cgraph.h" and "gimplify.h".
	(Gcc_backend::return_statement): Push and pop function.
	(Gcc_backend::label): Likewise.
	(Gcc_backend::function_defer_statement): Likewise.
	(Gcc_backend::switch_statement): Add function parameter.
	(Gcc_backend::block): Don't permit function to be NULL.
	(Gcc_backend::temporary_variable): Change go_assert to
	gcc_assert.
	(Gcc_backend::gc_root_variable): New function.
	(Gcc_backend::write_global_definitions): New function.
diff mbox

Patch

Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 209665)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -44,6 +44,7 @@  class Backend;
 class Export;
 class Import;
 class Bexpression;
+class Btype;
 class Bstatement;
 class Bblock;
 class Bvariable;
@@ -591,11 +592,6 @@  class Gogo
   Expression*
   runtime_error(int code, Location);
 
-  // Build a builtin struct with a list of fields.
-  static tree
-  builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
-		 int nfields, ...);
-
   // Mark a function declaration as a builtin library function.
   static void
   mark_fndecl_as_builtin_library(tree fndecl);
@@ -650,17 +646,18 @@  class Gogo
   Named_object*
   initialization_function_decl();
 
-  // Write the magic initialization function.
-  void
-  write_initialization_function(Named_object* fndecl, tree init_stmt_list);
+  // Create the magic initialization function.
+  Named_object*
+  create_initialization_function(Named_object* fndecl, Bstatement* code_stmt);
 
   // Initialize imported packages.
   void
-  init_imports(tree*);
+  init_imports(std::vector<Bstatement*>&);
 
   // Register variables with the garbage collector.
   void
-  register_gc_vars(const std::vector<Named_object*>&, tree*);
+  register_gc_vars(const std::vector<Named_object*>&,
+                   std::vector<Bstatement*>&);
 
   // Type used to map import names to packages.
   typedef std::map<std::string, Package*> Imports;
@@ -1086,7 +1083,7 @@  class Function
   get_or_make_decl(Gogo*, Named_object*);
 
   // Return the function's decl after it has been built.
-  tree
+  Bfunction*
   get_decl() const;
 
   // Set the function decl to hold a backend representation of the function
@@ -1675,7 +1672,7 @@  class Named_constant
   Named_constant(Type* type, Expression* expr, int iota_value,
 		 Location location)
     : type_(type), expr_(expr), iota_value_(iota_value), location_(location),
-      lowering_(false), is_sink_(false)
+      lowering_(false), is_sink_(false), bconst_(NULL)
   { }
 
   Type*
@@ -1737,6 +1734,10 @@  class Named_constant
   static void
   import_const(Import*, std::string*, Type**, Expression**);
 
+  // Get the backend representation of the constant value.
+  Bexpression*
+  get_backend(Gogo*, Named_object*);
+
  private:
   // The type of the constant.
   Type* type_;
@@ -1754,6 +1755,8 @@  class Named_constant
   bool lowering_;
   // Whether this constant is blank named and needs only type checking.
   bool is_sink_;
+  // The backend representation of the constant value.
+  Bexpression* bconst_;
 };
 
 // A type declaration.
@@ -2176,9 +2179,10 @@  class Named_object
   std::string
   get_id(Gogo*);
 
-  // Return a tree representing this object.
-  tree
-  get_tree(Gogo*, Named_object* function);
+  // Get the backend representation of this object.
+  void
+  get_backend(Gogo*, std::vector<Bexpression*>&, std::vector<Btype*>&,
+              std::vector<Bfunction*>&);
 
   // Define a type declaration.
   void
@@ -2219,8 +2223,6 @@  class Named_object
     Function_declaration* func_declaration_value;
     Package* package_value;
   } u_;
-  // The DECL tree for this object if we have already converted it.
-  tree tree_;
 };
 
 // A binding contour.  This binds names to objects.
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 209393)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -30,6 +30,7 @@  class Var_expression;
 class Temporary_reference_expression;
 class Set_and_use_temporary_expression;
 class String_expression;
+class Unary_expression;
 class Binary_expression;
 class Call_expression;
 class Func_expression;
@@ -327,6 +328,10 @@  class Expression
   static Expression*
   make_struct_composite_literal(Type*, Expression_list*, Location);
 
+  // Make an array composite literal.
+  static Expression*
+  make_array_composite_literal(Type*, Expression_list*, Location);
+
   // Make a slice composite literal.
   static Expression*
   make_slice_composite_literal(Type*, Expression_list*, Location);
@@ -533,6 +538,12 @@  class Expression
   Expression*
   deref();
 
+  // If this is a unary expression, return the Unary_expression
+  // structure.  Otherwise return NULL.
+  Unary_expression*
+  unary_expression()
+  { return this->convert<Unary_expression, EXPRESSION_UNARY>(); }
+
   // If this is a binary expression, return the Binary_expression
   // structure.  Otherwise return NULL.
   Binary_expression*
@@ -1286,6 +1297,143 @@  class String_expression : public Express
   Type* type_;
 };
 
+// A Unary expression.
+
+class Unary_expression : public Expression
+{
+ public:
+  Unary_expression(Operator op, Expression* expr, Location location)
+    : Expression(EXPRESSION_UNARY, location),
+      op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
+      expr_(expr), issue_nil_check_(false)
+  { }
+
+  // Return the operator.
+  Operator
+  op() const
+  { return this->op_; }
+
+  // Return the operand.
+  Expression*
+  operand() const
+  { return this->expr_; }
+
+  // Record that an address expression does not escape.
+  void
+  set_does_not_escape()
+  {
+    go_assert(this->op_ == OPERATOR_AND);
+    this->escapes_ = false;
+  }
+
+  // Record that this is an address expression which should create a
+  // temporary variable if necessary.  This is used for method calls.
+  void
+  set_create_temp()
+  {
+    go_assert(this->op_ == OPERATOR_AND);
+    this->create_temp_ = true;
+  }
+
+  // Record that this is an address expression of a GC root, which is a
+  // mutable composite literal.  This used for registering GC variables.
+  void
+  set_is_gc_root()
+  {
+    go_assert(this->op_ == OPERATOR_AND);
+    this->is_gc_root_ = true;
+  }
+
+  // Apply unary opcode OP to UNC, setting NC.  Return true if this
+  // could be done, false if not.  Issue errors for overflow.
+  static bool
+  eval_constant(Operator op, const Numeric_constant* unc,
+		Location, Numeric_constant* nc);
+
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->expr_, traverse); }
+
+  Expression*
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
+  bool
+  do_is_constant() const;
+
+  bool
+  do_is_immutable() const
+  {
+    return (this->expr_->is_immutable()
+	    || (this->op_ == OPERATOR_AND && this->expr_->is_variable()));
+  }
+
+  bool
+  do_numeric_constant_value(Numeric_constant*) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_unary(this->op_, this->expr_->copy(),
+				  this->location());
+  }
+
+  bool
+  do_must_eval_subexpressions_in_order(int*) const
+  { return this->op_ == OPERATOR_MULT; }
+
+  bool
+  do_is_addressable() const
+  { return this->op_ == OPERATOR_MULT; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+  void
+  do_issue_nil_check()
+  { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
+
+ private:
+  // The unary operator to apply.
+  Operator op_;
+  // Normally true.  False if this is an address expression which does
+  // not escape the current function.
+  bool escapes_;
+  // True if this is an address expression which should create a
+  // temporary variable if necessary.
+  bool create_temp_;
+  // True if this is an address expression for a GC root.  A GC root is a
+  // special struct composite literal that is mutable when addressed, meaning
+  // it cannot be represented as an immutable_struct in the backend.
+  bool is_gc_root_;
+  // The operand.
+  Expression* expr_;
+  // Whether or not to issue a nil check for this expression if its address
+  // is being taken.
+  bool issue_nil_check_;
+};
+
 // A binary expression.
 
 class Binary_expression : public Expression
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc	(revision 209393)
+++ gcc/go/gofrontend/statements.cc	(working copy)
@@ -434,15 +434,9 @@  Temporary_statement::do_get_backend(Tran
 {
   go_assert(this->bvariable_ == NULL);
 
-  // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
-  // until we have a better representation of the init function.
   Named_object* function = context->function();
-  Bfunction* bfunction;
-  if (function == NULL)
-    bfunction = NULL;
-  else
-    bfunction = tree_to_function(function->func_value()->get_decl());
-
+  go_assert(function != NULL);
+  Bfunction* bfunction = function->func_value()->get_decl();
   Btype* btype = this->type()->get_backend(context->gogo());
 
   Bexpression* binit;
@@ -2781,8 +2775,6 @@  Return_statement::do_get_backend(Transla
   Location loc = this->location();
 
   Function* function = context->function()->func_value();
-  tree fndecl = function->get_decl();
-
   Function::Results* results = function->result_variables();
   std::vector<Bexpression*> retvals;
   if (results != NULL && !results->empty())
@@ -2797,7 +2789,7 @@  Return_statement::do_get_backend(Transla
 	}
     }
 
-  return context->backend()->return_statement(tree_to_function(fndecl),
+  return context->backend()->return_statement(function->get_decl(),
 					      retvals, loc);
 }
 
@@ -3803,8 +3795,10 @@  Constant_switch_statement::do_get_backen
   this->clauses_->get_backend(context, break_label, &all_cases,
 			      &all_statements);
 
+  Bfunction* bfunction = context->function()->func_value()->get_decl();
   Bstatement* switch_statement;
-  switch_statement = context->backend()->switch_statement(switch_val_expr,
+  switch_statement = context->backend()->switch_statement(bfunction,
+							  switch_val_expr,
 							  all_cases,
 							  all_statements,
 							  this->location());
@@ -4980,7 +4974,9 @@  Select_clauses::get_backend(Translate_co
   std::vector<Bstatement*> statements;
   statements.reserve(2);
 
-  Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
+  Bfunction* bfunction = context->function()->func_value()->get_decl();
+  Bstatement* switch_stmt = context->backend()->switch_statement(bfunction,
+								 bcall,
 								 cases,
 								 clauses,
 								 location);
Index: gcc/go/gofrontend/gogo-tree.cc
===================================================================
--- gcc/go/gofrontend/gogo-tree.cc	(revision 209665)
+++ gcc/go/gofrontend/gogo-tree.cc	(working copy)
@@ -236,830 +236,6 @@  Gogo::define_builtin_function_trees()
 		 false);
 }
 
-// Add statements to INIT_STMT_LIST which run the initialization
-// functions for imported packages.  This is only used for the "main"
-// package.
-
-void
-Gogo::init_imports(tree* init_stmt_list)
-{
-  go_assert(this->is_main_package());
-
-  if (this->imported_init_fns_.empty())
-    return;
-
-  tree fntype = build_function_type(void_type_node, void_list_node);
-
-  // We must call them in increasing priority order.
-  std::vector<Import_init> v;
-  for (std::set<Import_init>::const_iterator p =
-	 this->imported_init_fns_.begin();
-       p != this->imported_init_fns_.end();
-       ++p)
-    v.push_back(*p);
-  std::sort(v.begin(), v.end());
-
-  for (std::vector<Import_init>::const_iterator p = v.begin();
-       p != v.end();
-       ++p)
-    {
-      std::string user_name = p->package_name() + ".init";
-      tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
-			     get_identifier_from_string(user_name),
-			     fntype);
-      const std::string& init_name(p->init_name());
-      SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name));
-      TREE_PUBLIC(decl) = 1;
-      DECL_EXTERNAL(decl) = 1;
-      append_to_statement_list(build_call_expr(decl, 0), init_stmt_list);
-    }
-}
-
-// Register global variables with the garbage collector.  We need to
-// register all variables which can hold a pointer value.  They become
-// roots during the mark phase.  We build a struct that is easy to
-// hook into a list of roots.
-
-// struct __go_gc_root_list
-// {
-//   struct __go_gc_root_list* __next;
-//   struct __go_gc_root
-//   {
-//     void* __decl;
-//     size_t __size;
-//   } __roots[];
-// };
-
-// The last entry in the roots array has a NULL decl field.
-
-void
-Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
-		       tree* init_stmt_list)
-{
-  if (var_gc.empty())
-    return;
-
-  size_t count = var_gc.size();
-
-  tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2,
-					"__next",
-					ptr_type_node,
-					"__size",
-					sizetype);
-
-  tree index_type = build_index_type(size_int(count));
-  tree array_type = build_array_type(root_type, index_type);
-
-  tree root_list_type = make_node(RECORD_TYPE);
-  root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list",
-					root_list_type, 2,
-					"__next",
-					build_pointer_type(root_list_type),
-					"__roots",
-					array_type);
-
-  // Build an initialier for the __roots array.
-
-  vec<constructor_elt, va_gc> *roots_init;
-  vec_alloc(roots_init, count + 1);
-
-  size_t i = 0;
-  for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
-       p != var_gc.end();
-       ++p, ++i)
-    {
-      vec<constructor_elt, va_gc> *init;
-      vec_alloc(init, 2);
-
-      constructor_elt empty = {NULL, NULL};
-      constructor_elt* elt = init->quick_push(empty);
-      tree field = TYPE_FIELDS(root_type);
-      elt->index = field;
-      Bvariable* bvar = (*p)->get_backend_variable(this, NULL);
-      tree decl = var_to_tree(bvar);
-      go_assert(TREE_CODE(decl) == VAR_DECL);
-      elt->value = build_fold_addr_expr(decl);
-
-      elt = init->quick_push(empty);
-      field = DECL_CHAIN(field);
-      elt->index = field;
-      elt->value = DECL_SIZE_UNIT(decl);
-
-      elt = roots_init->quick_push(empty);
-      elt->index = size_int(i);
-      elt->value = build_constructor(root_type, init);
-    }
-
-  // The list ends with a NULL entry.
-
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc(init, 2);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(root_type);
-  elt->index = field;
-  elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  elt->index = field;
-  elt->value = size_zero_node;
-
-  elt = roots_init->quick_push(empty);
-  elt->index = size_int(i);
-  elt->value = build_constructor(root_type, init);
-
-  // Build a constructor for the struct.
-
-  vec<constructor_elt, va_gc> *root_list_init;
-  vec_alloc(root_list_init, 2);
-
-  elt = root_list_init->quick_push(empty);
-  field = TYPE_FIELDS(root_list_type);
-  elt->index = field;
-  elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
-  elt = root_list_init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  elt->index = field;
-  elt->value = build_constructor(array_type, roots_init);
-
-  // Build a decl to register.
-
-  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
-			 create_tmp_var_name("gc"), root_list_type);
-  DECL_EXTERNAL(decl) = 0;
-  TREE_PUBLIC(decl) = 0;
-  TREE_STATIC(decl) = 1;
-  DECL_ARTIFICIAL(decl) = 1;
-  DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init);
-  rest_of_decl_compilation(decl, 1, 0);
-
-  static tree register_gc_fndecl;
-  tree call = Gogo::call_builtin(&register_gc_fndecl,
-                                 Linemap::predeclared_location(),
-                                 "__go_register_gc_roots",
-				 1,
-				 void_type_node,
-				 build_pointer_type(root_list_type),
-				 build_fold_addr_expr(decl));
-  if (call != error_mark_node)
-    append_to_statement_list(call, init_stmt_list);
-}
-
-// Create the magic initialization function.  INIT_STMT_LIST is the
-// code that it needs to run.
-
-void
-Gogo::write_initialization_function(Named_object* initfn, tree init_stmt_list)
-{
-  // Make sure that we thought we needed an initialization function,
-  // as otherwise we will not have reported it in the export data.
-  go_assert(this->is_main_package() || this->need_init_fn_);
-
-  if (initfn == NULL)
-    initfn = this->initialization_function_decl();
-
-  Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn);
-  Location loc = this->package_->location();
-  std::vector<Bvariable*> vars;
-  this->backend()->block(fndecl, NULL, vars, loc, loc);
-
-  if (!this->backend()->function_set_body(fndecl, tree_to_stat(init_stmt_list)))
-    {
-      go_assert(saw_errors());
-      return;
-    }
-  gimplify_function_tree(function_to_tree(fndecl));
-  cgraph_add_new_function(function_to_tree(fndecl), false);
-}
-
-// Search for references to VAR in any statements or called functions.
-
-class Find_var : public Traverse
-{
- public:
-  // A hash table we use to avoid looping.  The index is the name of a
-  // named object.  We only look through objects defined in this
-  // package.
-  typedef Unordered_set(const void*) Seen_objects;
-
-  Find_var(Named_object* var, Seen_objects* seen_objects)
-    : Traverse(traverse_expressions),
-      var_(var), seen_objects_(seen_objects), found_(false)
-  { }
-
-  // Whether the variable was found.
-  bool
-  found() const
-  { return this->found_; }
-
-  int
-  expression(Expression**);
-
- private:
-  // The variable we are looking for.
-  Named_object* var_;
-  // Names of objects we have already seen.
-  Seen_objects* seen_objects_;
-  // True if the variable was found.
-  bool found_;
-};
-
-// See if EXPR refers to VAR, looking through function calls and
-// variable initializations.
-
-int
-Find_var::expression(Expression** pexpr)
-{
-  Expression* e = *pexpr;
-
-  Var_expression* ve = e->var_expression();
-  if (ve != NULL)
-    {
-      Named_object* v = ve->named_object();
-      if (v == this->var_)
-	{
-	  this->found_ = true;
-	  return TRAVERSE_EXIT;
-	}
-
-      if (v->is_variable() && v->package() == NULL)
-	{
-	  Expression* init = v->var_value()->init();
-	  if (init != NULL)
-	    {
-	      std::pair<Seen_objects::iterator, bool> ins =
-		this->seen_objects_->insert(v);
-	      if (ins.second)
-		{
-		  // This is the first time we have seen this name.
-		  if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
-		    return TRAVERSE_EXIT;
-		}
-	    }
-	}
-    }
-
-  // We traverse the code of any function we see.  Note that this
-  // means that we will traverse the code of a function whose address
-  // is taken even if it is not called.
-  Func_expression* fe = e->func_expression();
-  if (fe != NULL)
-    {
-      const Named_object* f = fe->named_object();
-      if (f->is_function() && f->package() == NULL)
-	{
-	  std::pair<Seen_objects::iterator, bool> ins =
-	    this->seen_objects_->insert(f);
-	  if (ins.second)
-	    {
-	      // This is the first time we have seen this name.
-	      if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	    }
-	}
-    }
-
-  Temporary_reference_expression* tre = e->temporary_reference_expression();
-  if (tre != NULL)
-    {
-      Temporary_statement* ts = tre->statement();
-      Expression* init = ts->init();
-      if (init != NULL)
-	{
-	  std::pair<Seen_objects::iterator, bool> ins =
-	    this->seen_objects_->insert(ts);
-	  if (ins.second)
-	    {
-	      // This is the first time we have seen this temporary
-	      // statement.
-	      if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
-		return TRAVERSE_EXIT;
-	    }
-	}
-    }
-
-  return TRAVERSE_CONTINUE;
-}
-
-// Return true if EXPR, PREINIT, or DEP refers to VAR.
-
-static bool
-expression_requires(Expression* expr, Block* preinit, Named_object* dep,
-		    Named_object* var)
-{
-  Find_var::Seen_objects seen_objects;
-  Find_var find_var(var, &seen_objects);
-  if (expr != NULL)
-    Expression::traverse(&expr, &find_var);
-  if (preinit != NULL)
-    preinit->traverse(&find_var);
-  if (dep != NULL)
-    {
-      Expression* init = dep->var_value()->init();
-      if (init != NULL)
-	Expression::traverse(&init, &find_var);
-      if (dep->var_value()->has_pre_init())
-	dep->var_value()->preinit()->traverse(&find_var);
-    }
-
-  return find_var.found();
-}
-
-// Sort variable initializations.  If the initialization expression
-// for variable A refers directly or indirectly to the initialization
-// expression for variable B, then we must initialize B before A.
-
-class Var_init
-{
- public:
-  Var_init()
-    : var_(NULL), init_(NULL)
-  { }
-
-  Var_init(Named_object* var, Bstatement* init)
-    : var_(var), init_(init)
-  { }
-
-  // Return the variable.
-  Named_object*
-  var() const
-  { return this->var_; }
-
-  // Return the initialization expression.
-  Bstatement*
-  init() const
-  { return this->init_; }
-
- private:
-  // The variable being initialized.
-  Named_object* var_;
-  // The initialization statement.
-  Bstatement* init_;
-};
-
-typedef std::list<Var_init> Var_inits;
-
-// Sort the variable initializations.  The rule we follow is that we
-// emit them in the order they appear in the array, except that if the
-// initialization expression for a variable V1 depends upon another
-// variable V2 then we initialize V1 after V2.
-
-static void
-sort_var_inits(Gogo* gogo, Var_inits* var_inits)
-{
-  typedef std::pair<Named_object*, Named_object*> No_no;
-  typedef std::map<No_no, bool> Cache;
-  Cache cache;
-
-  Var_inits ready;
-  while (!var_inits->empty())
-    {
-      Var_inits::iterator p1 = var_inits->begin();
-      Named_object* var = p1->var();
-      Expression* init = var->var_value()->init();
-      Block* preinit = var->var_value()->preinit();
-      Named_object* dep = gogo->var_depends_on(var->var_value());
-
-      // Start walking through the list to see which variables VAR
-      // needs to wait for.
-      Var_inits::iterator p2 = p1;
-      ++p2;
-
-      for (; p2 != var_inits->end(); ++p2)
-	{
-	  Named_object* p2var = p2->var();
-	  No_no key(var, p2var);
-	  std::pair<Cache::iterator, bool> ins =
-	    cache.insert(std::make_pair(key, false));
-	  if (ins.second)
-	    ins.first->second = expression_requires(init, preinit, dep, p2var);
-	  if (ins.first->second)
-	    {
-	      // Check for cycles.
-	      key = std::make_pair(p2var, var);
-	      ins = cache.insert(std::make_pair(key, false));
-	      if (ins.second)
-		ins.first->second =
-		  expression_requires(p2var->var_value()->init(),
-				      p2var->var_value()->preinit(),
-				      gogo->var_depends_on(p2var->var_value()),
-				      var);
-	      if (ins.first->second)
-		{
-		  error_at(var->location(),
-			   ("initialization expressions for %qs and "
-			    "%qs depend upon each other"),
-			   var->message_name().c_str(),
-			   p2var->message_name().c_str());
-		  inform(p2->var()->location(), "%qs defined here",
-			 p2var->message_name().c_str());
-		  p2 = var_inits->end();
-		}
-	      else
-		{
-		  // We can't emit P1 until P2 is emitted.  Move P1.
-		  Var_inits::iterator p3 = p2;
-		  ++p3;
-		  var_inits->splice(p3, *var_inits, p1);
-		}
-	      break;
-	    }
-	}
-
-      if (p2 == var_inits->end())
-	{
-	  // VAR does not depends upon any other initialization expressions.
-
-	  // Check for a loop of VAR on itself.  We only do this if
-	  // INIT is not NULL and there is no dependency; when INIT is
-	  // NULL, it means that PREINIT sets VAR, which we will
-	  // interpret as a loop.
-	  if (init != NULL && dep == NULL
-	      && expression_requires(init, preinit, NULL, var))
-	    error_at(var->location(),
-		     "initialization expression for %qs depends upon itself",
-		     var->message_name().c_str());
-	  ready.splice(ready.end(), *var_inits, p1);
-	}
-    }
-
-  // Now READY is the list in the desired initialization order.
-  var_inits->swap(ready);
-}
-
-// Write out the global definitions.
-
-void
-Gogo::write_globals()
-{
-  this->build_interface_method_tables();
-
-  Bindings* bindings = this->current_bindings();
-
-  for (Bindings::const_declarations_iterator p = bindings->begin_declarations();
-       p != bindings->end_declarations();
-       ++p)
-    {
-      // If any function declarations needed a descriptor, make sure
-      // we build it.
-      Named_object* no = p->second;
-      if (no->is_function_declaration())
-	no->func_declaration_value()->build_backend_descriptor(this);
-    }
-
-  size_t count_definitions = bindings->size_definitions();
-  size_t count = count_definitions;
-
-  tree* vec = new tree[count];
-
-  Named_object* init_fndecl = NULL;
-  tree init_stmt_list = NULL_TREE;
-
-  if (this->is_main_package())
-    this->init_imports(&init_stmt_list);
-
-  // A list of variable initializations.
-  Var_inits var_inits;
-
-  // A list of variables which need to be registered with the garbage
-  // collector.
-  std::vector<Named_object*> var_gc;
-  var_gc.reserve(count);
-
-  tree var_init_stmt_list = NULL_TREE;
-  size_t i = 0;
-  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
-       p != bindings->end_definitions();
-       ++p, ++i)
-    {
-      Named_object* no = *p;
-
-      go_assert(i < count);
-
-      go_assert(!no->is_type_declaration() && !no->is_function_declaration());
-      // There is nothing to do for a package.
-      if (no->is_package())
-	{
-	  --i;
-	  --count;
-	  continue;
-	}
-
-      // There is nothing to do for an object which was imported from
-      // a different package into the global scope.
-      if (no->package() != NULL)
-	{
-	  --i;
-	  --count;
-	  continue;
-	}
-
-      // Skip blank named functions and constants.
-      if ((no->is_function() && no->func_value()->is_sink())
-	  || (no->is_const() && no->const_value()->is_sink()))
-        {
-          --i;
-          --count;
-          continue;
-        }
-
-      // There is nothing useful we can output for constants which
-      // have ideal or non-integral type.
-      if (no->is_const())
-	{
-	  Type* type = no->const_value()->type();
-	  if (type == NULL)
-	    type = no->const_value()->expr()->type();
-	  if (type->is_abstract() || type->integer_type() == NULL)
-	    {
-	      --i;
-	      --count;
-	      continue;
-	    }
-	}
-
-      if (!no->is_variable())
-	{
-	  vec[i] = no->get_tree(this, NULL);
-	  if (vec[i] == error_mark_node)
-	    {
-	      go_assert(saw_errors());
-	      --i;
-	      --count;
-	      continue;
-	    }
-	}
-      else
-	{
-	  Bvariable* var = no->get_backend_variable(this, NULL);
-	  vec[i] = var_to_tree(var);
-	  if (vec[i] == error_mark_node)
-	    {
-	      go_assert(saw_errors());
-	      --i;
-	      --count;
-	      continue;
-	    }
-
-	  // Check for a sink variable, which may be used to run an
-	  // initializer purely for its side effects.
-	  bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
-
-          Bstatement* var_init_stmt = NULL;
-	  if (!no->var_value()->has_pre_init())
-	    {
-              Bexpression* var_binit = no->var_value()->get_init(this, NULL);
-              if (var_binit == NULL)
-		;
-	      else if (TREE_CONSTANT(expr_to_tree(var_binit)))
-		{
-		  if (expression_requires(no->var_value()->init(), NULL,
-					  this->var_depends_on(no->var_value()),
-					  no))
-		    error_at(no->location(),
-			     "initialization expression for %qs depends "
-			     "upon itself",
-			     no->message_name().c_str());
-		  this->backend()->global_variable_set_init(var, var_binit);
-		}
-	      else if (is_sink)
-		var_init_stmt =
-                    this->backend()->expression_statement(var_binit);
-	      else
-                {
-                  Location loc = no->var_value()->location();
-                  Bexpression* var_expr =
-                      this->backend()->var_expression(var, loc);
-                  var_init_stmt =
-                      this->backend()->assignment_statement(var_expr, var_binit,
-                                                            loc);
-                }
-	    }
-	  else
-	    {
-	      // We are going to create temporary variables which
-	      // means that we need an fndecl.
-	      if (init_fndecl == NULL)
-		init_fndecl = this->initialization_function_decl();
-
-	      Bvariable* var_decl = is_sink ? NULL : var;
-              var_init_stmt =
-                  no->var_value()->get_init_block(this, init_fndecl, var_decl);
-	    }
-
-	  if (var_init_stmt != NULL)
-	    {
-	      if (no->var_value()->init() == NULL
-		  && !no->var_value()->has_pre_init())
-		append_to_statement_list(stat_to_tree(var_init_stmt),
-                                         &var_init_stmt_list);
-	      else
-		var_inits.push_back(Var_init(no, var_init_stmt));
-	    }
-	  else if (this->var_depends_on(no->var_value()) != NULL)
-	    {
-	      // This variable is initialized from something that is
-	      // not in its init or preinit.  This variable needs to
-	      // participate in dependency analysis sorting, in case
-	      // some other variable depends on this one.
-              Btype* int_btype =
-                  Type::lookup_integer_type("int")->get_backend(this);
-              Bexpression* zero = this->backend()->zero_expression(int_btype);
-              Bstatement* zero_stmt =
-                  this->backend()->expression_statement(zero);
-	      var_inits.push_back(Var_init(no, zero_stmt));
-	    }
-
-	  if (!is_sink && no->var_value()->type()->has_pointer())
-	    var_gc.push_back(no);
-	}
-    }
-
-  // Register global variables with the garbage collector.
-  this->register_gc_vars(var_gc, &init_stmt_list);
-
-  // Simple variable initializations, after all variables are
-  // registered.
-  append_to_statement_list(var_init_stmt_list, &init_stmt_list);
-
-  // Complex variable initializations, first sorting them into a
-  // workable order.
-  if (!var_inits.empty())
-    {
-      sort_var_inits(this, &var_inits);
-      for (Var_inits::const_iterator p = var_inits.begin();
-	   p != var_inits.end();
-	   ++p)
-	append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list);
-    }
-
-  // After all the variables are initialized, call the "init"
-  // functions if there are any.
-  for (std::vector<Named_object*>::const_iterator p =
-	 this->init_functions_.begin();
-       p != this->init_functions_.end();
-       ++p)
-    {
-      tree decl = (*p)->get_tree(this, NULL);
-      tree call = build_call_expr(decl, 0);
-      append_to_statement_list(call, &init_stmt_list);
-    }
-
-  // Set up a magic function to do all the initialization actions.
-  // This will be called if this package is imported.
-  if (init_stmt_list != NULL
-      || this->need_init_fn_
-      || this->is_main_package())
-    this->write_initialization_function(init_fndecl, init_stmt_list);
-
-  // We should not have seen any new bindings created during the
-  // conversion.
-  go_assert(count_definitions == this->current_bindings()->size_definitions());
-
-  // Pass everything back to the middle-end.
-
-  wrapup_global_declarations(vec, count);
-
-  finalize_compilation_unit();
-
-  check_global_declarations(vec, count);
-  emit_debug_global_declarations(vec, count);
-
-  delete[] vec;
-}
-
-// Get a tree for a named object.
-
-tree
-Named_object::get_tree(Gogo* gogo, Named_object* function)
-{
-  if (this->tree_ != NULL_TREE)
-    return this->tree_;
-
-  if (Gogo::is_erroneous_name(this->name_))
-    {
-      this->tree_ = error_mark_node;
-      return error_mark_node;
-    }
-
-  tree decl;
-  switch (this->classification_)
-    {
-    case NAMED_OBJECT_CONST:
-      {
-	Translate_context subcontext(gogo, function, NULL, NULL);
-	Type* type = this->u_.const_value->type();
-	Location loc = this->location();
-
-	Expression* const_ref = Expression::make_const_reference(this, loc);
-        Bexpression* const_decl =
-	  tree_to_expr(const_ref->get_tree(&subcontext));
-	if (type != NULL && type->is_numeric_type())
-	  {
-	    Btype* btype = type->get_backend(gogo);
-	    std::string name = this->get_id(gogo);
-            const_decl =
-	      gogo->backend()->named_constant_expression(btype, name,
-							 const_decl, loc);
-	  }
-	decl = expr_to_tree(const_decl);
-      }
-      break;
-
-    case NAMED_OBJECT_TYPE:
-      {
-	Named_type* named_type = this->u_.type_value;
-	tree type_tree = type_to_tree(named_type->get_backend(gogo));
-	if (type_tree == error_mark_node)
-	  decl = error_mark_node;
-	else
-	  {
-	    decl = TYPE_NAME(type_tree);
-	    go_assert(decl != NULL_TREE);
-
-	    // We need to produce a type descriptor for every named
-	    // type, and for a pointer to every named type, since
-	    // other files or packages might refer to them.  We need
-	    // to do this even for hidden types, because they might
-	    // still be returned by some function.  Simply calling the
-	    // type_descriptor method is enough to create the type
-	    // descriptor, even though we don't do anything with it.
-	    if (this->package_ == NULL)
-	      {
-		named_type->
-                  type_descriptor_pointer(gogo,
-					  Linemap::predeclared_location());
-		Type* pn = Type::make_pointer_type(named_type);
-		pn->type_descriptor_pointer(gogo,
-					    Linemap::predeclared_location());
-	      }
-	  }
-      }
-      break;
-
-    case NAMED_OBJECT_TYPE_DECLARATION:
-      error("reference to undefined type %qs",
-	    this->message_name().c_str());
-      return error_mark_node;
-
-    case NAMED_OBJECT_VAR:
-    case NAMED_OBJECT_RESULT_VAR:
-    case NAMED_OBJECT_SINK:
-      go_unreachable();
-
-    case NAMED_OBJECT_FUNC:
-      {
-	Function* func = this->u_.func_value;
-	decl = function_to_tree(func->get_or_make_decl(gogo, this));
-	if (decl != error_mark_node)
-	  {
-	    if (func->block() != NULL)
-	      {
-		if (DECL_STRUCT_FUNCTION(decl) == NULL)
-		  push_struct_function(decl);
-		else
-		  push_cfun(DECL_STRUCT_FUNCTION(decl));
-
-		cfun->function_start_locus = func->location().gcc_location();
-		cfun->function_end_locus =
-                  func->block()->end_location().gcc_location();
-
-		func->build(gogo, this);
-
-		gimplify_function_tree(decl);
-
-		cgraph_finalize_function(decl, true);
-
-		pop_cfun();
-	      }
-	  }
-      }
-      break;
-
-    case NAMED_OBJECT_ERRONEOUS:
-      decl = error_mark_node;
-      break;
-
-    default:
-      go_unreachable();
-    }
-
-  if (TREE_TYPE(decl) == error_mark_node)
-    decl = error_mark_node;
-
-  tree ret = decl;
-
-  this->tree_ = ret;
-
-  if (ret != error_mark_node)
-    go_preserve_from_gc(ret);
-
-  return ret;
-}
-
 // Get the backend representation.
 
 Bfunction*
@@ -1106,15 +282,6 @@  Function_declaration::get_or_make_decl(G
   return this->fndecl_;
 }
 
-// Return the function's decl after it has been built.
-
-tree
-Function::get_decl() const
-{
-  go_assert(this->fndecl_ != NULL);
-  return function_to_tree(this->fndecl_);
-}
-
 // Build the descriptor for a function declaration.  This won't
 // necessarily happen if the package has just a declaration for the
 // function and no other reference to it, but we may still need the
@@ -1214,55 +381,6 @@  go_type_for_mode(enum machine_mode mode,
     return NULL_TREE;
 }
 
-// Build a builtin struct with a list of fields.  The name is
-// STRUCT_NAME.  STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE
-// node; this exists so that the struct can have fields which point to
-// itself.  If PTYPE is not NULL, store the result in *PTYPE.  There
-// are NFIELDS fields.  Each field is a name (a const char*) followed
-// by a type (a tree).
-
-tree
-Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
-		     int nfields, ...)
-{
-  if (ptype != NULL && *ptype != NULL_TREE)
-    return *ptype;
-
-  va_list ap;
-  va_start(ap, nfields);
-
-  tree fields = NULL_TREE;
-  for (int i = 0; i < nfields; ++i)
-    {
-      const char* field_name = va_arg(ap, const char*);
-      tree type = va_arg(ap, tree);
-      if (type == error_mark_node)
-	{
-	  if (ptype != NULL)
-	    *ptype = error_mark_node;
-	  return error_mark_node;
-	}
-      tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL,
-			      get_identifier(field_name), type);
-      DECL_CHAIN(field) = fields;
-      fields = field;
-    }
-
-  va_end(ap);
-
-  if (struct_type == NULL_TREE)
-    struct_type = make_node(RECORD_TYPE);
-  finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE);
-
-  if (ptype != NULL)
-    {
-      go_preserve_from_gc(struct_type);
-      *ptype = struct_type;
-    }
-
-  return struct_type;
-}
-
 // Build a constructor for a slice.  SLICE_TYPE_TREE is the type of
 // the slice.  VALUES is the value pointer and COUNT is the number of
 // entries.  If CAPACITY is not NULL, it is the capacity; otherwise
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 209495)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -406,9 +406,9 @@  class Backend
   // integers, then STATEMENTS[i] is executed.  STATEMENTS[i] will
   // either end with a goto statement or will fall through into
   // STATEMENTS[i + 1].  CASES[i] is empty for the default clause,
-  // which need not be last.
+  // which need not be last.  FUNCTION is the current function.
   virtual Bstatement*
-  switch_statement(Bexpression* value,
+  switch_statement(Bfunction* function, Bexpression* value,
 		   const std::vector<std::vector<Bexpression*> >& cases,
 		   const std::vector<Bstatement*>& statements,
 		   Location) = 0;
@@ -534,6 +534,12 @@  class Backend
 		     bool address_is_taken, Location location,
 		     Bstatement** pstatement) = 0;
 
+  // Create a GC root variable. TYPE is the __go_gc_root_list struct described
+  // in Gogo::register_gc_vars.  INIT is the composite literal consisting of a
+  // pointer to the next GC root and the global variables registered.
+  virtual Bvariable*
+  gc_root_variable(Btype* type, Bexpression* init) = 0;
+
   // Create a named immutable initialized data structure.  This is
   // used for type descriptors, map descriptors, and function
   // descriptors.  This returns a Bvariable because it corresponds to
@@ -653,6 +659,16 @@  class Backend
   // true on success, false on failure.
   virtual bool
   function_set_body(Bfunction* function, Bstatement* code_stmt) = 0;
+
+  // Utility.
+
+  // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+  // FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+  virtual void
+  write_global_definitions(const std::vector<Btype*>& type_decls,
+                           const std::vector<Bexpression*>& constant_decls,
+                           const std::vector<Bfunction*>& function_decls,
+                           const std::vector<Bvariable*>& variable_decls) = 0;
 };
 
 // The backend interface has to define this function.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 209495)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -3578,127 +3578,7 @@  Expression::make_unsafe_cast(Type* type,
   return new Unsafe_type_conversion_expression(type, expr, location);
 }
 
-// Unary expressions.
-
-class Unary_expression : public Expression
-{
- public:
-  Unary_expression(Operator op, Expression* expr, Location location)
-    : Expression(EXPRESSION_UNARY, location),
-      op_(op), escapes_(true), create_temp_(false), expr_(expr),
-      issue_nil_check_(false)
-  { }
-
-  // Return the operator.
-  Operator
-  op() const
-  { return this->op_; }
-
-  // Return the operand.
-  Expression*
-  operand() const
-  { return this->expr_; }
-
-  // Record that an address expression does not escape.
-  void
-  set_does_not_escape()
-  {
-    go_assert(this->op_ == OPERATOR_AND);
-    this->escapes_ = false;
-  }
-
-  // Record that this is an address expression which should create a
-  // temporary variable if necessary.  This is used for method calls.
-  void
-  set_create_temp()
-  {
-    go_assert(this->op_ == OPERATOR_AND);
-    this->create_temp_ = true;
-  }
-
-  // Apply unary opcode OP to UNC, setting NC.  Return true if this
-  // could be done, false if not.  Issue errors for overflow.
-  static bool
-  eval_constant(Operator op, const Numeric_constant* unc,
-		Location, Numeric_constant* nc);
-
-  static Expression*
-  do_import(Import*);
-
- protected:
-  int
-  do_traverse(Traverse* traverse)
-  { return Expression::traverse(&this->expr_, traverse); }
-
-  Expression*
-  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
-  Expression*
-  do_flatten(Gogo*, Named_object*, Statement_inserter*);
-
-  bool
-  do_is_constant() const;
-
-  bool
-  do_is_immutable() const
-  { return this->expr_->is_immutable()
-      || (this->op_ == OPERATOR_AND && this->expr_->is_variable()); }
-
-  bool
-  do_numeric_constant_value(Numeric_constant*) const;
-
-  Type*
-  do_type();
-
-  void
-  do_determine_type(const Type_context*);
-
-  void
-  do_check_types(Gogo*);
-
-  Expression*
-  do_copy()
-  {
-    return Expression::make_unary(this->op_, this->expr_->copy(),
-				  this->location());
-  }
-
-  bool
-  do_must_eval_subexpressions_in_order(int*) const
-  { return this->op_ == OPERATOR_MULT; }
-
-  bool
-  do_is_addressable() const
-  { return this->op_ == OPERATOR_MULT; }
-
-  tree
-  do_get_tree(Translate_context*);
-
-  void
-  do_export(Export*) const;
-
-  void
-  do_dump_expression(Ast_dump_context*) const;
-
-  void
-  do_issue_nil_check()
-  { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
-
- private:
-  // The unary operator to apply.
-  Operator op_;
-  // Normally true.  False if this is an address expression which does
-  // not escape the current function.
-  bool escapes_;
-  // True if this is an address expression which should create a
-  // temporary variable if necessary.
-  bool create_temp_;
-  // The operand.
-  Expression* expr_;
-  // Whether or not to issue a nil check for this expression if its address
-  // is being taken.
-  bool issue_nil_check_;
-};
+// Class Unary_expression.
 
 // If we are taking the address of a composite literal, and the
 // contents are not constant, then we want to make a heap expression
@@ -4214,11 +4094,18 @@  Unary_expression::do_get_tree(Translate_
 	    }
 	}
 
-      // Build a decl for a constant constructor.
-      if ((this->expr_->is_composite_literal()
+      if (this->is_gc_root_)
+	{
+	  // Build a decl for a GC root variable.  GC roots are mutable, so they
+	  // cannot be represented as an immutable_struct in the backend.
+	  Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
+	  bexpr = gogo->backend()->var_expression(gc_root, loc);
+	}
+      else if ((this->expr_->is_composite_literal()
            || this->expr_->string_expression() != NULL)
           && this->expr_->is_immutable())
         {
+	  // Build a decl for a constant constructor.
           static unsigned int counter;
           char buf[100];
           snprintf(buf, sizeof buf, "C%u", counter);
@@ -12508,6 +12395,14 @@  Fixed_array_construction_expression::do_
   return expr_to_tree(this->get_constructor(context, btype));
 }
 
+Expression*
+Expression::make_array_composite_literal(Type* type, Expression_list* vals,
+                                         Location location)
+{
+  go_assert(type->array_type() != NULL && !type->is_slice_type());
+  return new Fixed_array_construction_expression(type, NULL, vals, location);
+}
+
 // Construct a slice.
 
 class Slice_construction_expression : public Array_construction_expression
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 209665)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -575,6 +575,164 @@  Gogo::current_bindings() const
     return this->globals_;
 }
 
+// Add statements to INIT_STMTS which run the initialization
+// functions for imported packages.  This is only used for the "main"
+// package.
+
+void
+Gogo::init_imports(std::vector<Bstatement*>& init_stmts)
+{
+  go_assert(this->is_main_package());
+
+  if (this->imported_init_fns_.empty())
+    return;
+
+  Location unknown_loc = Linemap::unknown_location();
+  Function_type* func_type =
+      Type::make_function_type(NULL, NULL, NULL, unknown_loc);
+  Btype* fntype = func_type->get_backend_fntype(this);
+
+  // We must call them in increasing priority order.
+  std::vector<Import_init> v;
+  for (std::set<Import_init>::const_iterator p =
+	 this->imported_init_fns_.begin();
+       p != this->imported_init_fns_.end();
+       ++p)
+    v.push_back(*p);
+  std::sort(v.begin(), v.end());
+
+  // We build calls to the init functions, which take no arguments.
+  std::vector<Bexpression*> empty_args;
+  for (std::vector<Import_init>::const_iterator p = v.begin();
+       p != v.end();
+       ++p)
+    {
+      std::string user_name = p->package_name() + ".init";
+      const std::string& init_name(p->init_name());
+
+      Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name,
+                                                   true, true, true, false,
+                                                   false, unknown_loc);
+      Bexpression* pfunc_code =
+          this->backend()->function_code_expression(pfunc, unknown_loc);
+      Bexpression* pfunc_call =
+          this->backend()->call_expression(pfunc_code, empty_args, unknown_loc);
+      init_stmts.push_back(this->backend()->expression_statement(pfunc_call));
+    }
+}
+
+// Register global variables with the garbage collector.  We need to
+// register all variables which can hold a pointer value.  They become
+// roots during the mark phase.  We build a struct that is easy to
+// hook into a list of roots.
+
+// struct __go_gc_root_list
+// {
+//   struct __go_gc_root_list* __next;
+//   struct __go_gc_root
+//   {
+//     void* __decl;
+//     size_t __size;
+//   } __roots[];
+// };
+
+// The last entry in the roots array has a NULL decl field.
+
+void
+Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
+		       std::vector<Bstatement*>& init_stmts)
+{
+  if (var_gc.empty())
+    return;
+
+  Type* pvt = Type::make_pointer_type(Type::make_void_type());
+  Type* uint_type = Type::lookup_integer_type("uint");
+  Struct_type* root_type = Type::make_builtin_struct_type(2,
+                                                          "__decl", pvt,
+                                                          "__size", uint_type);
+
+  Location builtin_loc = Linemap::predeclared_location();
+  size_t count = var_gc.size();
+  mpz_t lenval;
+  mpz_init_set_ui(lenval, count);
+  Expression* length = Expression::make_integer(&lenval, NULL, builtin_loc);
+  mpz_clear(lenval);
+
+  Array_type* root_array_type = Type::make_array_type(root_type, length);
+  Type* ptdt = Type::make_type_descriptor_ptr_type();
+  Struct_type* root_list_type =
+      Type::make_builtin_struct_type(2,
+                                     "__next", ptdt,
+                                     "__roots", root_array_type);
+
+  // Build an initializer for the __roots array.
+
+  Expression_list* roots_init = new Expression_list();
+
+  size_t i = 0;
+  for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
+       p != var_gc.end();
+       ++p, ++i)
+    {
+      Expression_list* init = new Expression_list();
+
+      Location no_loc = (*p)->location();
+      Expression* decl = Expression::make_var_reference(*p, no_loc);
+      Expression* decl_addr =
+          Expression::make_unary(OPERATOR_AND, decl, no_loc);
+      init->push_back(decl_addr);
+
+      Expression* decl_size =
+          Expression::make_type_info(decl->type(), Expression::TYPE_INFO_SIZE);
+      init->push_back(decl_size);
+
+      Expression* root_ctor =
+          Expression::make_struct_composite_literal(root_type, init, no_loc);
+      roots_init->push_back(root_ctor);
+    }
+
+  // The list ends with a NULL entry.
+
+  Expression_list* null_init = new Expression_list();
+  Expression* nil = Expression::make_nil(builtin_loc);
+  null_init->push_back(nil);
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zero = Expression::make_integer(&zval, NULL, builtin_loc);
+  mpz_clear(zval);
+  null_init->push_back(zero);
+
+  Expression* null_root_ctor =
+      Expression::make_struct_composite_literal(root_type, null_init,
+                                                builtin_loc);
+  roots_init->push_back(null_root_ctor);
+
+  // Build a constructor for the struct.
+
+  Expression_list* root_list_init = new Expression_list();
+  root_list_init->push_back(nil);
+
+  Expression* roots_ctor =
+      Expression::make_array_composite_literal(root_array_type, roots_init,
+                                               builtin_loc);
+  root_list_init->push_back(roots_ctor);
+
+  Expression* root_list_ctor =
+      Expression::make_struct_composite_literal(root_list_type, root_list_init,
+                                                builtin_loc);
+
+  Expression* root_addr = Expression::make_unary(OPERATOR_AND, root_list_ctor,
+                                                 builtin_loc);
+  root_addr->unary_expression()->set_is_gc_root();
+  Expression* register_roots = Runtime::make_call(Runtime::REGISTER_GC_ROOTS,
+                                                  builtin_loc, 1, root_addr);
+
+  Translate_context context(this, NULL, NULL, NULL);
+  Bexpression* bcall = tree_to_expr(register_roots->get_tree(&context));
+  init_stmts.push_back(this->backend()->expression_statement(bcall));
+}
+
 // Get the name to use for the import control function.  If there is a
 // global function or variable, then we know that that name must be
 // unique in the link, and we use it as the basis for our name.
@@ -614,6 +772,521 @@  Gogo::initialization_function_decl()
   return Named_object::make_function(name, NULL, initfn);
 }
 
+// Create the magic initialization function.  CODE_STMT is the
+// code that it needs to run.
+
+Named_object*
+Gogo::create_initialization_function(Named_object* initfn,
+				     Bstatement* code_stmt)
+{
+  // Make sure that we thought we needed an initialization function,
+  // as otherwise we will not have reported it in the export data.
+  go_assert(this->is_main_package() || this->need_init_fn_);
+
+  if (initfn == NULL)
+    initfn = this->initialization_function_decl();
+
+  // Bind the initialization function code to a block.
+  Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn);
+  Location pkg_loc = this->package_->location();
+  std::vector<Bvariable*> vars;
+  this->backend()->block(fndecl, NULL, vars, pkg_loc, pkg_loc);
+
+  if (!this->backend()->function_set_body(fndecl, code_stmt))
+    {
+      go_assert(saw_errors());
+      return NULL;
+    }
+  return initfn;
+}
+
+// Search for references to VAR in any statements or called functions.
+
+class Find_var : public Traverse
+{
+ public:
+  // A hash table we use to avoid looping.  The index is the name of a
+  // named object.  We only look through objects defined in this
+  // package.
+  typedef Unordered_set(const void*) Seen_objects;
+
+  Find_var(Named_object* var, Seen_objects* seen_objects)
+    : Traverse(traverse_expressions),
+      var_(var), seen_objects_(seen_objects), found_(false)
+  { }
+
+  // Whether the variable was found.
+  bool
+  found() const
+  { return this->found_; }
+
+  int
+  expression(Expression**);
+
+ private:
+  // The variable we are looking for.
+  Named_object* var_;
+  // Names of objects we have already seen.
+  Seen_objects* seen_objects_;
+  // True if the variable was found.
+  bool found_;
+};
+
+// See if EXPR refers to VAR, looking through function calls and
+// variable initializations.
+
+int
+Find_var::expression(Expression** pexpr)
+{
+  Expression* e = *pexpr;
+
+  Var_expression* ve = e->var_expression();
+  if (ve != NULL)
+    {
+      Named_object* v = ve->named_object();
+      if (v == this->var_)
+	{
+	  this->found_ = true;
+	  return TRAVERSE_EXIT;
+	}
+
+      if (v->is_variable() && v->package() == NULL)
+	{
+	  Expression* init = v->var_value()->init();
+	  if (init != NULL)
+	    {
+	      std::pair<Seen_objects::iterator, bool> ins =
+		this->seen_objects_->insert(v);
+	      if (ins.second)
+		{
+		  // This is the first time we have seen this name.
+		  if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
+		    return TRAVERSE_EXIT;
+		}
+	    }
+	}
+    }
+
+  // We traverse the code of any function we see.  Note that this
+  // means that we will traverse the code of a function whose address
+  // is taken even if it is not called.
+  Func_expression* fe = e->func_expression();
+  if (fe != NULL)
+    {
+      const Named_object* f = fe->named_object();
+      if (f->is_function() && f->package() == NULL)
+	{
+	  std::pair<Seen_objects::iterator, bool> ins =
+	    this->seen_objects_->insert(f);
+	  if (ins.second)
+	    {
+	      // This is the first time we have seen this name.
+	      if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
+		return TRAVERSE_EXIT;
+	    }
+	}
+    }
+
+  Temporary_reference_expression* tre = e->temporary_reference_expression();
+  if (tre != NULL)
+    {
+      Temporary_statement* ts = tre->statement();
+      Expression* init = ts->init();
+      if (init != NULL)
+	{
+	  std::pair<Seen_objects::iterator, bool> ins =
+	    this->seen_objects_->insert(ts);
+	  if (ins.second)
+	    {
+	      // This is the first time we have seen this temporary
+	      // statement.
+	      if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
+		return TRAVERSE_EXIT;
+	    }
+	}
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Return true if EXPR, PREINIT, or DEP refers to VAR.
+
+static bool
+expression_requires(Expression* expr, Block* preinit, Named_object* dep,
+		    Named_object* var)
+{
+  Find_var::Seen_objects seen_objects;
+  Find_var find_var(var, &seen_objects);
+  if (expr != NULL)
+    Expression::traverse(&expr, &find_var);
+  if (preinit != NULL)
+    preinit->traverse(&find_var);
+  if (dep != NULL)
+    {
+      Expression* init = dep->var_value()->init();
+      if (init != NULL)
+	Expression::traverse(&init, &find_var);
+      if (dep->var_value()->has_pre_init())
+	dep->var_value()->preinit()->traverse(&find_var);
+    }
+
+  return find_var.found();
+}
+
+// Sort variable initializations.  If the initialization expression
+// for variable A refers directly or indirectly to the initialization
+// expression for variable B, then we must initialize B before A.
+
+class Var_init
+{
+ public:
+  Var_init()
+    : var_(NULL), init_(NULL)
+  { }
+
+  Var_init(Named_object* var, Bstatement* init)
+    : var_(var), init_(init)
+  { }
+
+  // Return the variable.
+  Named_object*
+  var() const
+  { return this->var_; }
+
+  // Return the initialization expression.
+  Bstatement*
+  init() const
+  { return this->init_; }
+
+ private:
+  // The variable being initialized.
+  Named_object* var_;
+  // The initialization statement.
+  Bstatement* init_;
+};
+
+typedef std::list<Var_init> Var_inits;
+
+// Sort the variable initializations.  The rule we follow is that we
+// emit them in the order they appear in the array, except that if the
+// initialization expression for a variable V1 depends upon another
+// variable V2 then we initialize V1 after V2.
+
+static void
+sort_var_inits(Gogo* gogo, Var_inits* var_inits)
+{
+  typedef std::pair<Named_object*, Named_object*> No_no;
+  typedef std::map<No_no, bool> Cache;
+  Cache cache;
+
+  Var_inits ready;
+  while (!var_inits->empty())
+    {
+      Var_inits::iterator p1 = var_inits->begin();
+      Named_object* var = p1->var();
+      Expression* init = var->var_value()->init();
+      Block* preinit = var->var_value()->preinit();
+      Named_object* dep = gogo->var_depends_on(var->var_value());
+
+      // Start walking through the list to see which variables VAR
+      // needs to wait for.
+      Var_inits::iterator p2 = p1;
+      ++p2;
+
+      for (; p2 != var_inits->end(); ++p2)
+	{
+	  Named_object* p2var = p2->var();
+	  No_no key(var, p2var);
+	  std::pair<Cache::iterator, bool> ins =
+	    cache.insert(std::make_pair(key, false));
+	  if (ins.second)
+	    ins.first->second = expression_requires(init, preinit, dep, p2var);
+	  if (ins.first->second)
+	    {
+	      // Check for cycles.
+	      key = std::make_pair(p2var, var);
+	      ins = cache.insert(std::make_pair(key, false));
+	      if (ins.second)
+		ins.first->second =
+		  expression_requires(p2var->var_value()->init(),
+				      p2var->var_value()->preinit(),
+				      gogo->var_depends_on(p2var->var_value()),
+				      var);
+	      if (ins.first->second)
+		{
+		  error_at(var->location(),
+			   ("initialization expressions for %qs and "
+			    "%qs depend upon each other"),
+			   var->message_name().c_str(),
+			   p2var->message_name().c_str());
+		  inform(p2->var()->location(), "%qs defined here",
+			 p2var->message_name().c_str());
+		  p2 = var_inits->end();
+		}
+	      else
+		{
+		  // We can't emit P1 until P2 is emitted.  Move P1.
+		  Var_inits::iterator p3 = p2;
+		  ++p3;
+		  var_inits->splice(p3, *var_inits, p1);
+		}
+	      break;
+	    }
+	}
+
+      if (p2 == var_inits->end())
+	{
+	  // VAR does not depends upon any other initialization expressions.
+
+	  // Check for a loop of VAR on itself.  We only do this if
+	  // INIT is not NULL and there is no dependency; when INIT is
+	  // NULL, it means that PREINIT sets VAR, which we will
+	  // interpret as a loop.
+	  if (init != NULL && dep == NULL
+	      && expression_requires(init, preinit, NULL, var))
+	    error_at(var->location(),
+		     "initialization expression for %qs depends upon itself",
+		     var->message_name().c_str());
+	  ready.splice(ready.end(), *var_inits, p1);
+	}
+    }
+
+  // Now READY is the list in the desired initialization order.
+  var_inits->swap(ready);
+}
+
+// Write out the global definitions.
+
+void
+Gogo::write_globals()
+{
+  this->build_interface_method_tables();
+
+  Bindings* bindings = this->current_bindings();
+
+  for (Bindings::const_declarations_iterator p = bindings->begin_declarations();
+       p != bindings->end_declarations();
+       ++p)
+    {
+      // If any function declarations needed a descriptor, make sure
+      // we build it.
+      Named_object* no = p->second;
+      if (no->is_function_declaration())
+	no->func_declaration_value()->build_backend_descriptor(this);
+    }
+
+  // Lists of globally declared types, variables, constants, and functions
+  // that must be defined.
+  std::vector<Btype*> type_decls;
+  std::vector<Bvariable*> var_decls;
+  std::vector<Bexpression*> const_decls;
+  std::vector<Bfunction*> func_decls;
+
+  // The init function declaration, if necessary.
+  Named_object* init_fndecl = NULL;
+
+  std::vector<Bstatement*> init_stmts;
+  std::vector<Bstatement*> var_init_stmts;
+
+  if (this->is_main_package())
+    this->init_imports(init_stmts);
+
+  // A list of variable initializations.
+  Var_inits var_inits;
+
+  // A list of variables which need to be registered with the garbage
+  // collector.
+  size_t count_definitions = bindings->size_definitions();
+  std::vector<Named_object*> var_gc;
+  var_gc.reserve(count_definitions);
+
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    {
+      Named_object* no = *p;
+      go_assert(!no->is_type_declaration() && !no->is_function_declaration());
+
+      // There is nothing to do for a package.
+      if (no->is_package())
+        continue;
+
+      // There is nothing to do for an object which was imported from
+      // a different package into the global scope.
+      if (no->package() != NULL)
+        continue;
+
+      // Skip blank named functions and constants.
+      if ((no->is_function() && no->func_value()->is_sink())
+	  || (no->is_const() && no->const_value()->is_sink()))
+        continue;
+
+      // There is nothing useful we can output for constants which
+      // have ideal or non-integral type.
+      if (no->is_const())
+        {
+          Type* type = no->const_value()->type();
+          if (type == NULL)
+            type = no->const_value()->expr()->type();
+          if (type->is_abstract() || !type->is_numeric_type())
+            continue;
+        }
+
+      if (!no->is_variable())
+        no->get_backend(this, const_decls, type_decls, func_decls);
+      else
+	{
+          Variable* var = no->var_value();
+	  Bvariable* bvar = no->get_backend_variable(this, NULL);
+          var_decls.push_back(bvar);
+
+	  // Check for a sink variable, which may be used to run an
+	  // initializer purely for its side effects.
+	  bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
+
+          Bstatement* var_init_stmt = NULL;
+	  if (!var->has_pre_init())
+	    {
+              Bexpression* var_binit = var->get_init(this, NULL);
+
+              // If the backend representation of the variable initializer is
+              // constant, we can just set the initial value using
+              // global_var_set_init instead of during the init() function.
+              // The initializer is constant if it is the zero-value of the
+              // variable's type or if the initial value is an immutable value
+              // that is not copied to the heap.
+              bool is_constant_initializer = false;
+              if (var->init() == NULL)
+                is_constant_initializer = true;
+              else
+                {
+                  Type* var_type = var->type();
+                  Expression* init = var->init();
+                  Expression* init_cast =
+                      Expression::make_cast(var_type, init, var->location());
+                  is_constant_initializer =
+                      init_cast->is_immutable() && !var_type->has_pointer();
+                }
+
+              if (var_binit == NULL)
+		;
+	      else if (is_constant_initializer)
+		{
+		  if (expression_requires(var->init(), NULL,
+					  this->var_depends_on(var), no))
+		    error_at(no->location(),
+			     "initialization expression for %qs depends "
+			     "upon itself",
+			     no->message_name().c_str());
+		  this->backend()->global_variable_set_init(bvar, var_binit);
+		}
+	      else if (is_sink)
+	        var_init_stmt =
+                    this->backend()->expression_statement(var_binit);
+	      else
+                {
+                  Location loc = var->location();
+                  Bexpression* var_expr =
+                      this->backend()->var_expression(bvar, loc);
+                  var_init_stmt =
+                      this->backend()->assignment_statement(var_expr, var_binit,
+                                                            loc);
+                }
+	    }
+	  else
+	    {
+	      // We are going to create temporary variables which
+	      // means that we need an fndecl.
+              if (init_fndecl == NULL)
+		init_fndecl = this->initialization_function_decl();
+
+	      Bvariable* var_decl = is_sink ? NULL : bvar;
+	      var_init_stmt = var->get_init_block(this, init_fndecl, var_decl);
+	    }
+
+	  if (var_init_stmt != NULL)
+	    {
+	      if (var->init() == NULL && !var->has_pre_init())
+                var_init_stmts.push_back(var_init_stmt);
+	      else
+                var_inits.push_back(Var_init(no, var_init_stmt));
+	    }
+	  else if (this->var_depends_on(var) != NULL)
+	    {
+	      // This variable is initialized from something that is
+	      // not in its init or preinit.  This variable needs to
+	      // participate in dependency analysis sorting, in case
+	      // some other variable depends on this one.
+              Btype* btype = no->var_value()->type()->get_backend(this);
+              Bexpression* zero = this->backend()->zero_expression(btype);
+              Bstatement* zero_stmt =
+                  this->backend()->expression_statement(zero);
+	      var_inits.push_back(Var_init(no, zero_stmt));
+	    }
+
+	  if (!is_sink && var->type()->has_pointer())
+	    var_gc.push_back(no);
+	}
+    }
+
+  // Register global variables with the garbage collector.
+  this->register_gc_vars(var_gc, init_stmts);
+
+  // Simple variable initializations, after all variables are
+  // registered.
+  init_stmts.push_back(this->backend()->statement_list(var_init_stmts));
+
+  // Complete variable initializations, first sorting them into a
+  // workable order.
+  if (!var_inits.empty())
+    {
+      sort_var_inits(this, &var_inits);
+      for (Var_inits::const_iterator p = var_inits.begin();
+           p != var_inits.end();
+           ++p)
+        init_stmts.push_back(p->init());
+    }
+
+  // After all the variables are initialized, call the init
+  // functions if there are any.  Init functions take no arguments, so
+  // we pass in EMPTY_ARGS to call them.
+  std::vector<Bexpression*> empty_args;
+  for (std::vector<Named_object*>::const_iterator p =
+           this->init_functions_.begin();
+       p != this->init_functions_.end();
+       ++p)
+    {
+      Location func_loc = (*p)->location();
+      Function* func = (*p)->func_value();
+      Bfunction* initfn = func->get_or_make_decl(this, *p);
+      Bexpression* func_code =
+          this->backend()->function_code_expression(initfn, func_loc);
+      Bexpression* call = this->backend()->call_expression(func_code,
+                                                           empty_args,
+                                                           func_loc);
+      init_stmts.push_back(this->backend()->expression_statement(call));
+    }
+
+  // Set up a magic function to do all the initialization actions.
+  // This will be called if this package is imported.
+  Bstatement* init_fncode = this->backend()->statement_list(init_stmts);
+  if (this->need_init_fn_ || this->is_main_package())
+    {
+      init_fndecl =
+	this->create_initialization_function(init_fndecl, init_fncode);
+      if (init_fndecl != NULL)
+	func_decls.push_back(init_fndecl->func_value()->get_decl());
+    }
+
+  // We should not have seen any new bindings created during the conversion.
+  go_assert(count_definitions == this->current_bindings()->size_definitions());
+
+  // Define all globally declared values.
+  if (!saw_errors())
+    this->backend()->write_global_definitions(type_decls, const_decls,
+					      func_decls, var_decls);
+}
+
 // Return the current block.
 
 Block*
@@ -4182,6 +4855,15 @@  Function::get_or_make_decl(Gogo* gogo, N
   return this->fndecl_;
 }
 
+// Return the function's decl after it has been built.
+
+Bfunction*
+Function::get_decl() const
+{
+  go_assert(this->fndecl_ != NULL);
+  return this->fndecl_;
+}
+
 // Build the backend representation for the function code.
 
 void
@@ -5266,8 +5948,7 @@  Variable::get_init_block(Gogo* gogo, Nam
 	{
           Location loc = this->location();
           Expression* val_expr =
-              Expression::convert_for_assignment(gogo, this->type(),
-                                                 this->init_, this->location());
+              Expression::make_cast(this->type(), this->init_, loc);
           Bexpression* val = tree_to_expr(val_expr->get_tree(&context));
           Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc);
           decl_init = gogo->backend()->assignment_statement(var_ref, val, loc);
@@ -5353,8 +6034,7 @@  Variable::get_backend_variable(Gogo* gog
 	    }
 	  else
 	    {
-	      tree fndecl = function->func_value()->get_decl();
-	      Bfunction* bfunction = tree_to_function(fndecl);
+	      Bfunction* bfunction = function->func_value()->get_decl();
 	      bool is_address_taken = (this->is_non_escaping_address_taken_
 				       && !this->is_in_heap());
 	      if (is_parameter)
@@ -5391,8 +6071,7 @@  Result_variable::get_backend_variable(Go
 	  if (this->is_in_heap())
 	    type = Type::make_pointer_type(type);
 	  Btype* btype = type->get_backend(gogo);
-	  tree fndecl = function->func_value()->get_decl();
-	  Bfunction* bfunction = tree_to_function(fndecl);
+	  Bfunction* bfunction = function->func_value()->get_decl();
 	  std::string n = Gogo::unpack_hidden_name(name);
 	  bool is_address_taken = (this->is_non_escaping_address_taken_
 				   && !this->is_in_heap());
@@ -5482,6 +6161,33 @@  Named_constant::import_const(Import* imp
   imp->require_c_string(";\n");
 }
 
+// Get the backend representation.
+
+Bexpression*
+Named_constant::get_backend(Gogo* gogo, Named_object* const_no)
+{
+  if (this->bconst_ == NULL)
+    {
+      Translate_context subcontext(gogo, NULL, NULL, NULL);
+      Type* type = this->type();
+      Location loc = this->location();
+
+      Expression* const_ref = Expression::make_const_reference(const_no, loc);
+      Bexpression* const_decl =
+	tree_to_expr(const_ref->get_tree(&subcontext));
+      if (type != NULL && type->is_numeric_type())
+	{
+	  Btype* btype = type->get_backend(gogo);
+	  std::string name = const_no->get_id(gogo);
+	  const_decl =
+	    gogo->backend()->named_constant_expression(btype, name,
+						       const_decl, loc);
+	}
+      this->bconst_ = const_decl;
+    }
+  return this->bconst_;
+}
+
 // Add a method.
 
 Named_object*
@@ -5552,8 +6258,7 @@  Unknown_name::set_real_named_object(Name
 Named_object::Named_object(const std::string& name,
 			   const Package* package,
 			   Classification classification)
-  : name_(name), package_(package), classification_(classification),
-    tree_(NULL)
+  : name_(name), package_(package), classification_(classification)
 {
   if (Gogo::is_sink_name(name))
     go_assert(classification == NAMED_OBJECT_SINK);
@@ -5928,6 +6633,72 @@  Named_object::get_id(Gogo* gogo)
   return decl_name;
 }
 
+// Get the backend representation for this named object.
+
+void
+Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
+                          std::vector<Btype*>& type_decls,
+                          std::vector<Bfunction*>& func_decls)
+{
+  switch (this->classification_)
+    {
+    case NAMED_OBJECT_CONST:
+      if (!Gogo::is_erroneous_name(this->name_))
+	const_decls.push_back(this->u_.const_value->get_backend(gogo, this));
+      break;
+
+    case NAMED_OBJECT_TYPE:
+      {
+        Named_type* named_type = this->u_.type_value;
+	if (!Gogo::is_erroneous_name(this->name_))
+	  type_decls.push_back(named_type->get_backend(gogo));
+
+        // We need to produce a type descriptor for every named
+        // type, and for a pointer to every named type, since
+        // other files or packages might refer to them.  We need
+        // to do this even for hidden types, because they might
+        // still be returned by some function.  Simply calling the
+        // type_descriptor method is enough to create the type
+        // descriptor, even though we don't do anything with it.
+        if (this->package_ == NULL)
+          {
+            named_type->
+                type_descriptor_pointer(gogo, Linemap::predeclared_location());
+            Type* pn = Type::make_pointer_type(named_type);
+            pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
+          }
+      }
+      break;
+
+    case NAMED_OBJECT_TYPE_DECLARATION:
+      error("reference to undefined type %qs",
+	    this->message_name().c_str());
+      return;
+
+    case NAMED_OBJECT_VAR:
+    case NAMED_OBJECT_RESULT_VAR:
+    case NAMED_OBJECT_SINK:
+      go_unreachable();
+
+    case NAMED_OBJECT_FUNC:
+      {
+	Function* func = this->u_.func_value;
+	if (!Gogo::is_erroneous_name(this->name_))
+	  func_decls.push_back(func->get_or_make_decl(gogo, this));
+
+	if (func->block() != NULL)
+	  func->build(gogo, this);
+      }
+      break;
+
+    case NAMED_OBJECT_ERRONEOUS:
+      break;
+
+    default:
+      go_unreachable();
+    }
+}
+
 // Class Bindings.
 
 Bindings::Bindings(Bindings* enclosing)
@@ -6400,8 +7171,7 @@  Label::get_backend_label(Translate_conte
   if (this->blabel_ == NULL)
     {
       Function* function = context->function()->func_value();
-      tree fndecl = function->get_decl();
-      Bfunction* bfunction = tree_to_function(fndecl);
+      Bfunction* bfunction = function->get_decl();
       this->blabel_ = context->backend()->label(bfunction, this->name_,
 						this->location_);
     }
@@ -6427,8 +7197,7 @@  Unnamed_label::get_blabel(Translate_cont
   if (this->blabel_ == NULL)
     {
       Function* function = context->function()->func_value();
-      tree fndecl = function->get_decl();
-      Bfunction* bfunction = tree_to_function(fndecl);
+      Bfunction* bfunction = function->get_decl();
       this->blabel_ = context->backend()->label(bfunction, "",
 						this->location_);
     }
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 209665)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -29,9 +29,11 @@ 
 #include "stor-layout.h"
 #include "varasm.h"
 #include "tree-iterator.h"
+#include "cgraph.h"
 #include "convert.h"
 #include "basic-block.h"
 #include "gimple-expr.h"
+#include "gimplify.h"
 #include "toplev.h"
 #include "output.h"
 #include "real.h"
@@ -317,7 +319,7 @@  class Gcc_backend : public Backend
 	       Location);
 
   Bstatement*
-  switch_statement(Bexpression* value,
+  switch_statement(Bfunction* function, Bexpression* value,
 		   const std::vector<std::vector<Bexpression*> >& cases,
 		   const std::vector<Bstatement*>& statements,
 		   Location);
@@ -376,6 +378,9 @@  class Gcc_backend : public Backend
 		     Location, Bstatement**);
 
   Bvariable*
+  gc_root_variable(Btype*, Bexpression*);
+
+  Bvariable*
   immutable_struct(const std::string&, bool, bool, Btype*, Location);
 
   void
@@ -420,6 +425,12 @@  class Gcc_backend : public Backend
   bool
   function_set_body(Bfunction* function, Bstatement* code_stmt);
 
+  void
+  write_global_definitions(const std::vector<Btype*>&,
+                           const std::vector<Bexpression*>&,
+                           const std::vector<Bfunction*>&,
+                           const std::vector<Bvariable*>&);
+
  private:
   // Make a Bexpression from a tree.
   Bexpression*
@@ -1709,6 +1720,7 @@  Gcc_backend::return_statement(Bfunction*
   tree result = DECL_RESULT(fntree);
   if (result == error_mark_node)
     return this->error_statement();
+
   tree ret;
   if (vals.empty())
     ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node,
@@ -1732,7 +1744,14 @@  Gcc_backend::return_statement(Bfunction*
       // statement.
       tree stmt_list = NULL_TREE;
       tree rettype = TREE_TYPE(result);
+
+      if (DECL_STRUCT_FUNCTION(fntree) == NULL)
+	push_struct_function(fntree);
+      else
+	push_cfun(DECL_STRUCT_FUNCTION(fntree));
       tree rettmp = create_tmp_var(rettype, "RESULT");
+      pop_cfun();
+
       tree field = TYPE_FIELDS(rettype);
       for (std::vector<Bexpression*>::const_iterator p = vals.begin();
 	   p != vals.end();
@@ -1818,6 +1837,7 @@  Gcc_backend::if_statement(Bexpression* c
 
 Bstatement*
 Gcc_backend::switch_statement(
+    Bfunction* function,
     Bexpression* value,
     const std::vector<std::vector<Bexpression*> >& cases,
     const std::vector<Bstatement*>& statements,
@@ -1825,6 +1845,12 @@  Gcc_backend::switch_statement(
 {
   gcc_assert(cases.size() == statements.size());
 
+  tree decl = function->get_tree();
+  if (DECL_STRUCT_FUNCTION(decl) == NULL)
+    push_struct_function(decl);
+  else
+    push_cfun(DECL_STRUCT_FUNCTION(decl));
+
   tree stmt_list = NULL_TREE;
   std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
   for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
@@ -1864,6 +1890,7 @@  Gcc_backend::switch_statement(
 	  append_to_statement_list(t, &stmt_list);
 	}
     }
+  pop_cfun();
 
   tree tv = value->get_tree();
   if (tv == error_mark_node)
@@ -1922,13 +1949,7 @@  Gcc_backend::block(Bfunction* function,
   tree block_tree = make_node(BLOCK);
   if (enclosing == NULL)
     {
-      // FIXME: Permitting FUNCTION to be NULL is a temporary measure
-      // until we have a proper representation of the init function.
-      tree fndecl;
-      if (function == NULL)
-	fndecl = current_function_decl;
-      else
-	fndecl = function->get_tree();
+      tree fndecl = function->get_tree();
       gcc_assert(fndecl != NULL_TREE);
 
       // We may have already created a block for local variables when
@@ -1982,7 +2003,6 @@  Gcc_backend::block(Bfunction* function,
                               void_type_node, BLOCK_VARS(block_tree),
                               NULL_TREE, block_tree);
   TREE_SIDE_EFFECTS(bind_tree) = 1;
-
   return new Bblock(bind_tree);
 }
 
@@ -2214,7 +2234,7 @@  Gcc_backend::temporary_variable(Bfunctio
       return this->error_variable();
     }
 
-  go_assert(function != NULL);
+  gcc_assert(function != NULL);
   tree decl = function->get_tree();
 
   tree var;
@@ -2263,6 +2283,28 @@  Gcc_backend::temporary_variable(Bfunctio
   return new Bvariable(var);
 }
 
+// Make a GC root variable.
+
+Bvariable*
+Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
+{
+  tree type_tree = type->get_tree();
+  tree init_tree = init->get_tree();
+  if (type_tree == error_mark_node || init_tree == error_mark_node)
+    return this->error_variable();
+
+  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+                         create_tmp_var_name("gc"), type_tree);
+  DECL_EXTERNAL(decl) = 0;
+  TREE_PUBLIC(decl) = 0;
+  TREE_STATIC(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+  DECL_INITIAL(decl) = init_tree;
+  rest_of_decl_compilation(decl, 1, 0);
+
+  return new Bvariable(decl);
+}
+
 // Create a named immutable initialized data structure.
 
 Bvariable*
@@ -2277,9 +2319,9 @@  Gcc_backend::immutable_struct(const std:
 			 get_identifier_from_string(name),
 			 build_qualified_type(type_tree, TYPE_QUAL_CONST));
   TREE_STATIC(decl) = 1;
+  TREE_USED(decl) = 1;
   TREE_READONLY(decl) = 1;
   TREE_CONSTANT(decl) = 1;
-  TREE_USED(decl) = 1;
   DECL_ARTIFICIAL(decl) = 1;
   if (!is_hidden)
     TREE_PUBLIC(decl) = 1;
@@ -2369,7 +2411,17 @@  Gcc_backend::label(Bfunction* function,
 {
   tree decl;
   if (name.empty())
-    decl = create_artificial_label(location.gcc_location());
+    {
+      tree func_tree = function->get_tree();
+      if (DECL_STRUCT_FUNCTION(func_tree) == NULL)
+	push_struct_function(func_tree);
+      else
+	push_cfun(DECL_STRUCT_FUNCTION(func_tree));
+
+      decl = create_artificial_label(location.gcc_location());
+
+      pop_cfun();
+    }
   else
     {
       tree id = get_identifier_from_string(name);
@@ -2477,11 +2529,18 @@  Gcc_backend::function_defer_statement(Bf
 {
   tree undefer_tree = undefer->get_tree();
   tree defer_tree = defer->get_tree();
+  tree fntree = function->get_tree();
 
   if (undefer_tree == error_mark_node
-      || defer_tree == error_mark_node)
+      || defer_tree == error_mark_node
+      || fntree == error_mark_node)
     return this->error_statement();
 
+  if (DECL_STRUCT_FUNCTION(fntree) == NULL)
+    push_struct_function(fntree);
+  else
+    push_cfun(DECL_STRUCT_FUNCTION(fntree));
+
   tree stmt_list = NULL;
   Blabel* blabel = this->label(function, "", location);
   Bstatement* label_def = this->label_definition_statement(blabel);
@@ -2494,6 +2553,7 @@  Gcc_backend::function_defer_statement(Bf
   tree try_catch =
       build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
   append_to_statement_list(try_catch, &stmt_list);
+  pop_cfun();
 
   return this->make_statement(stmt_list);
 }
@@ -2538,6 +2598,88 @@  Gcc_backend::function_set_body(Bfunction
   return true;
 }
 
+// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+// FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+
+void
+Gcc_backend::write_global_definitions(
+    const std::vector<Btype*>& type_decls,
+    const std::vector<Bexpression*>& constant_decls,
+    const std::vector<Bfunction*>& function_decls,
+    const std::vector<Bvariable*>& variable_decls)
+{
+  size_t count_definitions = type_decls.size() + constant_decls.size()
+      + function_decls.size() + variable_decls.size();
+
+  tree* defs = new tree[count_definitions];
+
+  // Convert all non-erroneous declarations into Gimple form.
+  size_t i = 0;
+  for (std::vector<Bvariable*>::const_iterator p = variable_decls.begin();
+       p != variable_decls.end();
+       ++p)
+    {
+      if ((*p)->get_tree() != error_mark_node)
+        {
+          defs[i] = (*p)->get_tree();
+          go_preserve_from_gc(defs[i]);
+          ++i;
+        }
+    }
+
+  for (std::vector<Btype*>::const_iterator p = type_decls.begin();
+       p != type_decls.end();
+       ++p)
+    {
+      tree type_tree = (*p)->get_tree();
+      if (type_tree != error_mark_node
+          && IS_TYPE_OR_DECL_P(type_tree))
+        {
+          defs[i] = TYPE_NAME(type_tree);
+          gcc_assert(defs[i] != NULL);
+          go_preserve_from_gc(defs[i]);
+          ++i;
+        }
+    }
+  for (std::vector<Bexpression*>::const_iterator p = constant_decls.begin();
+       p != constant_decls.end();
+       ++p)
+    {
+      if ((*p)->get_tree() != error_mark_node)
+        {
+          defs[i] = (*p)->get_tree();
+          go_preserve_from_gc(defs[i]);
+          ++i;
+        }
+    }
+  for (std::vector<Bfunction*>::const_iterator p = function_decls.begin();
+       p != function_decls.end();
+       ++p)
+    {
+      tree decl = (*p)->get_tree();
+      if (decl != error_mark_node)
+        {
+          go_preserve_from_gc(decl);
+          gimplify_function_tree(decl);
+          cgraph_finalize_function(decl, true);
+
+          defs[i] = decl;
+          ++i;
+        }
+    }
+
+  // Pass everything back to the middle-end.
+
+  wrapup_global_declarations(defs, i);
+
+  finalize_compilation_unit();
+
+  check_global_declarations(defs, i);
+  emit_debug_global_declarations(defs, i);
+
+  delete[] defs;
+}
+
 // The single backend.
 
 static Gcc_backend gcc_backend;