Index: gcc/go/Make-lang.in
===================================================================
--- gcc/go/Make-lang.in	(revision 253311)
+++ gcc/go/Make-lang.in	(working copy)
@@ -68,6 +68,7 @@ GO_OBJS = \
 	go/import.o \
 	go/import-archive.o \
 	go/lex.o \
+	go/names.o \
 	go/parse.o \
 	go/runtime.o \
 	go/statements.o \
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 253311)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@
-5989ef1cd0add98f107839759a5bc57f34354d39
+048914caa26b34eebabd0423ed48ee3ac34c919c
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/escape.cc
===================================================================
--- gcc/go/gofrontend/escape.cc	(revision 253311)
+++ gcc/go/gofrontend/escape.cc	(working copy)
@@ -575,7 +575,7 @@ debug_function_name(Named_object* fn)
 
   // Extract #.
   std::string name = Gogo::unpack_hidden_name(fn->name());
-  int closure_num = (int)strtol(name.substr(6).c_str(), NULL, 0);
+  int closure_num = Gogo::nested_function_num(fn->name());
   closure_num++;
 
   name = Gogo::unpack_hidden_name(enclosing->name());
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 253311)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -1299,28 +1299,12 @@ Func_descriptor_expression::do_get_backe
     return context->backend()->var_expression(this->dvar_, VE_rvalue, loc);
 
   Gogo* gogo = context->gogo();
-  std::string var_name;
+  std::string var_name(gogo->function_descriptor_name(no));
   bool is_descriptor = false;
   if (no->is_function_declaration()
       && !no->func_declaration_value()->asm_name().empty()
       && Linemap::is_predeclared_location(no->location()))
-    {
-      if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.")
-	var_name = no->func_declaration_value()->asm_name() + "_descriptor";
-      else
-	var_name = no->func_declaration_value()->asm_name() + "$descriptor";
-      is_descriptor = true;
-    }
-  else
-    {
-      if (no->package() == NULL)
-	var_name = gogo->pkgpath_symbol();
-      else
-	var_name = no->package()->pkgpath_symbol();
-      var_name.push_back('.');
-      var_name.append(Gogo::unpack_hidden_name(no->name()));
-      var_name.append("$descriptor");
-    }
+    is_descriptor = true;
 
   Btype* btype = this->type()->get_backend(gogo);
 
@@ -4348,27 +4332,23 @@ Unary_expression::do_get_backend(Transla
 	    }
 	}
 
-      static unsigned int counter;
-      char buf[100];
       if (this->is_gc_root_ || this->is_slice_init_)
 	{
+	  std::string var_name;
 	  bool copy_to_heap = false;
 	  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.
-	      static unsigned int root_counter;
-	      snprintf(buf, sizeof buf, "gc%u", root_counter);
-	      ++root_counter;
+	      var_name = gogo->gc_root_name();
 	    }
 	  else
 	    {
 	      // Build a decl for a slice value initializer.  An immutable slice
 	      // value initializer may have to be copied to the heap if it
 	      // contains pointers in a non-constant context.
-	      snprintf(buf, sizeof buf, "C%u", counter);
-	      ++counter;
+	      var_name = gogo->initializer_name();
 
 	      Array_type* at = this->expr_->type()->array_type();
 	      go_assert(at != NULL);
@@ -4379,12 +4359,12 @@ Unary_expression::do_get_backend(Transla
 	      // read-only, because the program is permitted to change it.
 	      copy_to_heap = context->function() != NULL;
 	    }
-          std::string asm_name(go_selectively_encode_id(buf));
+	  std::string asm_name(go_selectively_encode_id(var_name));
 	  Bvariable* implicit =
-              gogo->backend()->implicit_variable(buf, asm_name,
+              gogo->backend()->implicit_variable(var_name, asm_name,
                                                  btype, true, copy_to_heap,
                                                  false, 0);
-	  gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
+	  gogo->backend()->implicit_variable_set_init(implicit, var_name, btype,
 						      true, copy_to_heap, false,
 						      bexpr);
 	  bexpr = gogo->backend()->var_expression(implicit, VE_rvalue, loc);
@@ -4407,16 +4387,13 @@ Unary_expression::do_get_backend(Transla
 		|| this->expr_->string_expression() != NULL)
 	       && this->expr_->is_static_initializer())
         {
-	  // Build a decl for a constant constructor.
-          snprintf(buf, sizeof buf, "C%u", counter);
-          ++counter;
-
-          std::string asm_name(go_selectively_encode_id(buf));
+	  std::string var_name(gogo->initializer_name());
+	  std::string asm_name(go_selectively_encode_id(var_name));
           Bvariable* decl =
-              gogo->backend()->immutable_struct(buf, asm_name,
+              gogo->backend()->immutable_struct(var_name, asm_name,
                                                 true, false, btype, loc);
-          gogo->backend()->immutable_struct_set_init(decl, buf, true, false,
-                                                     btype, loc, bexpr);
+          gogo->backend()->immutable_struct_set_init(decl, var_name, true,
+						     false, btype, loc, bexpr);
           bexpr = gogo->backend()->var_expression(decl, VE_rvalue, loc);
         }
 
@@ -15403,10 +15380,9 @@ Interface_mtable_expression::do_get_back
   const Typed_identifier_list* interface_methods = this->itype_->methods();
   go_assert(!interface_methods->empty());
 
-  std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
-			      + this->itype_->mangled_name(gogo)
-			      + "__"
-			      + this->type_->mangled_name(gogo));
+  std::string mangled_name =
+    gogo->interface_method_table_name(this->itype_, this->type_,
+				      this->is_pointer_);
 
   // Set is_public if we are converting a named type to an interface
   // type that is defined in the same package as the named type, and
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 253311)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -868,32 +868,6 @@ Gogo::register_gc_vars(const std::vector
   init_stmts.push_back(this->backend()->expression_statement(init_bfn, 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.
-
-const std::string&
-Gogo::get_init_fn_name()
-{
-  if (this->init_fn_name_.empty())
-    {
-      go_assert(this->package_ != NULL);
-      if (this->is_main_package())
-	{
-	  // Use a name which the runtime knows.
-	  this->init_fn_name_ = "__go_init_main";
-	}
-      else
-	{
-	  std::string s = this->pkgpath_symbol();
-	  s.append("..import");
-	  this->init_fn_name_ = s;
-	}
-    }
-
-  return this->init_fn_name_;
-}
-
 // Build the decl for the initialization function.
 
 Named_object*
@@ -1774,11 +1748,7 @@ Gogo::start_function(const std::string&
 		    "func init must have no arguments and no return values");
       // There can be multiple "init" functions, so give them each a
       // different name.
-      static int init_count;
-      char buf[30];
-      snprintf(buf, sizeof buf, ".$init%d", init_count);
-      ++init_count;
-      nested_name = buf;
+      nested_name = this->init_function_name();
       pname = &nested_name;
       is_init = true;
     }
@@ -1787,22 +1757,15 @@ Gogo::start_function(const std::string&
   else
     {
       // Invent a name for a nested function.
-      static int nested_count;
-      char buf[30];
-      snprintf(buf, sizeof buf, ".$nested%d", nested_count);
-      ++nested_count;
-      nested_name = buf;
+      nested_name = this->nested_function_name();
       pname = &nested_name;
     }
 
   Named_object* ret;
   if (Gogo::is_sink_name(*pname))
     {
-      static int sink_count;
-      char buf[30];
-      snprintf(buf, sizeof buf, ".$sink%d", sink_count);
-      ++sink_count;
-      ret = Named_object::make_function(buf, NULL, function);
+      std::string sname(this->sink_function_name());
+      ret = Named_object::make_function(sname, NULL, function);
       ret->func_value()->set_is_sink();
 
       if (!type->is_method())
@@ -1845,11 +1808,8 @@ Gogo::start_function(const std::string&
 	{
 	  // Redefinition error.  Invent a name to avoid knockon
 	  // errors.
-	  static int redefinition_count;
-	  char buf[30];
-	  snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
-	  ++redefinition_count;
-	  ret = this->package_->bindings()->add_function(buf, NULL, function);
+	  std::string rname(this->redefined_function_name());
+	  ret = this->package_->bindings()->add_function(rname, NULL, function);
 	}
     }
   else
@@ -2274,47 +2234,6 @@ Gogo::record_interface_type(Interface_ty
   this->interface_types_.push_back(itype);
 }
 
-// Return an erroneous name that indicates that an error has already
-// been reported.
-
-std::string
-Gogo::erroneous_name()
-{
-  static int erroneous_count;
-  char name[50];
-  snprintf(name, sizeof name, "$erroneous%d", erroneous_count);
-  ++erroneous_count;
-  return name;
-}
-
-// Return whether a name is an erroneous name.
-
-bool
-Gogo::is_erroneous_name(const std::string& name)
-{
-  return name.compare(0, 10, "$erroneous") == 0;
-}
-
-// Return a name for a thunk object.
-
-std::string
-Gogo::thunk_name()
-{
-  static int thunk_count;
-  char thunk_name[50];
-  snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
-  ++thunk_count;
-  return thunk_name;
-}
-
-// Return whether a function is a thunk.
-
-bool
-Gogo::is_thunk(const Named_object* no)
-{
-  return no->name().compare(0, 6, "$thunk") == 0;
-}
-
 // Define the global names.  We do this only after parsing all the
 // input files, because the program might define the global names
 // itself.
@@ -4195,10 +4114,10 @@ Build_recover_thunks::function(Named_obj
   if (orig_fntype->is_varargs())
     new_fntype->set_is_varargs();
 
-  std::string name = orig_no->name();
+  Type* rtype = NULL;
   if (orig_fntype->is_method())
-    name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo);
-  name += "$recover";
+    rtype = orig_fntype->receiver()->type();
+  std::string name(gogo->recover_thunk_name(orig_no->name(), rtype));
   Named_object *new_no = gogo->start_function(name, new_fntype, false,
 					      location);
   Function *new_func = new_no->func_value();
@@ -5449,29 +5368,10 @@ Function::get_or_make_decl(Gogo* gogo, N
         {
 	  if (!this->is_unnamed_type_stub_method_)
 	    is_visible = true;
-          std::string pkgpath = gogo->pkgpath_symbol();
-          if (this->type_->is_method()
-              && Gogo::is_hidden_name(no->name())
-              && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
-            {
-              // This is a method we created for an unexported
-              // method of an imported embedded type.  We need to
-              // use the pkgpath of the imported package to avoid
-              // a possible name collision.  See bug478 for a test
-              // case.
-	      std::string p = Gogo::hidden_name_pkgpath(no->name());
-	      pkgpath = gogo->pkgpath_symbol_for_package(p);
-            }
-
-          asm_name = pkgpath;
-          asm_name.append(1, '.');
-          asm_name.append(Gogo::unpack_hidden_name(no->name()));
-          if (this->type_->is_method())
-            {
-              asm_name.append(1, '.');
-              Type* rtype = this->type_->receiver()->type();
-              asm_name.append(rtype->mangled_name(gogo));
-            }
+	  Type* rtype = NULL;
+	  if (this->type_->is_method())
+	    rtype = this->type_->receiver()->type();
+	  asm_name = gogo->function_asm_name(no->name(), NULL, rtype);
         }
 
       if (!this->asm_name_.empty())
@@ -5510,8 +5410,8 @@ Function::get_or_make_decl(Gogo* gogo, N
 	disable_split_stack = true;
 
       // Encode name if asm_name not already set at this point
-      if (asm_name.empty() && go_id_needs_encoding(no->get_id(gogo)))
-        asm_name = go_encode_id(no->get_id(gogo));
+      if (asm_name.empty())
+	asm_name = gogo->unexported_function_asm_name(no->name());
 
       // This should go into a unique section if that has been
       // requested elsewhere, or if this is a nointerface function.
@@ -5553,30 +5453,12 @@ Function_declaration::get_or_make_decl(G
 
       std::string asm_name;
       if (this->asm_name_.empty())
-        {
-          asm_name = (no->package() == NULL
-		      ? gogo->pkgpath_symbol()
-		      : no->package()->pkgpath_symbol());
-	  if (this->fntype_->is_method()
-	      && Gogo::is_hidden_name(no->name())
-	      && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
-	    {
-	      // This is a method created for an unexported method of
-	      // an imported embedded type.  Use the pkgpath of the
-	      // imported package.  This matches code in
-	      // Function::get_or_make_decl, above.
-	      std::string p = Gogo::hidden_name_pkgpath(no->name());
-	      asm_name = gogo->pkgpath_symbol_for_package(p);
-	    }
-          asm_name.append(1, '.');
-          asm_name.append(Gogo::unpack_hidden_name(no->name()));
-          if (this->fntype_->is_method())
-            {
-              asm_name.append(1, '.');
-              Type* rtype = this->fntype_->receiver()->type();
-              asm_name.append(rtype->mangled_name(gogo));
-            }
-        }
+	{
+	  Type* rtype = NULL;
+	  if (this->fntype_->is_method())
+	    rtype = this->fntype_->receiver()->type();
+	  asm_name = gogo->function_asm_name(no->name(), no->package(), rtype);
+	}
       else if (go_id_needs_encoding(no->get_id(gogo)))
         asm_name = go_encode_id(no->get_id(gogo));
 
@@ -6815,18 +6697,8 @@ Variable::get_backend_variable(Gogo* gog
 				   : gogo->package_name());
 	      var_name.push_back('.');
 	      var_name.append(n);
-              std::string asm_name;
-              if (Gogo::is_hidden_name(name))
-                asm_name = var_name;
-              else
-                {
-                  asm_name = package != NULL
-                      ? package->pkgpath_symbol()
-                      : gogo->pkgpath_symbol();
-                  asm_name.push_back('.');
-                  asm_name.append(n);
-                }
-	      asm_name = go_encode_id(asm_name);
+
+              std::string asm_name(gogo->global_var_asm_name(name, package));
 
 	      bool is_hidden = Gogo::is_hidden_name(name);
 	      // Hack to export runtime.writeBarrier.  FIXME.
@@ -7416,23 +7288,18 @@ Named_object::get_backend_variable(Gogo*
     go_unreachable();
 }
 
-
 // Return the external identifier for this object.
 
 std::string
 Named_object::get_id(Gogo* gogo)
 {
-  go_assert(!this->is_variable() && !this->is_result_variable());
+  go_assert(!this->is_variable()
+	    && !this->is_result_variable()
+	    && !this->is_type());
   std::string decl_name;
   if (this->is_function_declaration()
       && !this->func_declaration_value()->asm_name().empty())
     decl_name = this->func_declaration_value()->asm_name();
-  else if (this->is_type()
-	   && Linemap::is_predeclared_location(this->type_value()->location()))
-    {
-      // We don't need the package name for builtin types.
-      decl_name = Gogo::unpack_hidden_name(this->name_);
-    }
   else
     {
       std::string package_name;
@@ -7466,22 +7333,6 @@ Named_object::get_id(Gogo* gogo)
 	  decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
 	}
     }
-  if (this->is_type())
-    {
-      unsigned int index;
-      const Named_object* in_function = this->type_value()->in_function(&index);
-      if (in_function != NULL)
-	{
-	  decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
-	  if (index > 0)
-	    {
-	      char buf[30];
-	      snprintf(buf, sizeof buf, "%u", index);
-	      decl_name += '$';
-	      decl_name += buf;
-	    }
-	}
-    }
   return decl_name;
 }
 
Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 253311)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -506,26 +506,6 @@ class Gogo
   void
   mark_locals_used();
 
-  // Return a name to use for an error case.  This should only be used
-  // after reporting an error, and is used to avoid useless knockon
-  // errors.
-  static std::string
-  erroneous_name();
-
-  // Return whether the name indicates an error.
-  static bool
-  is_erroneous_name(const std::string&);
-
-  // Return a name to use for a thunk function.  A thunk function is
-  // one we create during the compilation, for a go statement or a
-  // defer statement or a method expression.
-  static std::string
-  thunk_name();
-
-  // Return whether an object is a thunk.
-  static bool
-  is_thunk(const Named_object*);
-
   // Note that we've seen an interface type.  This is used to build
   // all required interface method tables.
   void
@@ -781,10 +761,112 @@ class Gogo
   Expression*
   allocate_memory(Type *type, Location);
 
+  // Return the assembler name to use for an exported function, a
+  // method, or a function/method declaration.
+  std::string
+  function_asm_name(const std::string& go_name, const Package*,
+		    const Type* receiver);
+
+  // Return the assembler name to use for an unexported function.
+  std::string
+  unexported_function_asm_name(const std::string& go_name);
+
+  // Return the name to use for a function descriptor.
+  std::string
+  function_descriptor_name(Named_object*);
+
+  // Return the name to use for a generated stub method.
+  std::string
+  stub_method_name(const std::string& method_name);
+
+  // Return the names of the hash and equality functions for TYPE.
+  void
+  specific_type_function_names(const Type*, const Named_type*,
+			       std::string* hash_name,
+			       std::string* equal_name);
+
+  // Return the assembler name to use for a global variable.
+  std::string
+  global_var_asm_name(const std::string& go_name, const Package*);
+
+  // Return a name to use for an error case.  This should only be used
+  // after reporting an error, and is used to avoid useless knockon
+  // errors.
+  static std::string
+  erroneous_name();
+
+  // Return whether the name indicates an error.
+  static bool
+  is_erroneous_name(const std::string&);
+
+  // Return a name to use for a thunk function.  A thunk function is
+  // one we create during the compilation, for a go statement or a
+  // defer statement or a method expression.
+  static std::string
+  thunk_name();
+
+  // Return whether an object is a thunk.
+  static bool
+  is_thunk(const Named_object*);
+
+  // Return the name to use for an init function.
+  std::string
+  init_function_name();
+
+  // Return the name to use for a nested function.
+  static std::string
+  nested_function_name();
+
+  // Return the index of a nested function name.
+  static int
+  nested_function_num(const std::string&);
+
+  // Return the name to use for a sink funciton.
+  std::string
+  sink_function_name();
+
+  // Return the name to use for an (erroneous) redefined function.
+  std::string
+  redefined_function_name();
+
+  // Return the name for use for a recover thunk.
+  std::string
+  recover_thunk_name(const std::string& name, const Type* rtype);
+
+  // Return the name to use for the GC root variable.
+  std::string
+  gc_root_name();
+
+  // Return the name to use for a composite literal or string
+  // initializer.
+  std::string
+  initializer_name();
+
+  // Return the name of the variable used to represent the zero value
+  // of a map.
+  std::string
+  map_zero_value_name();
+
   // Get the name of the magic initialization function.
   const std::string&
   get_init_fn_name();
 
+  // Return the name for a type descriptor symbol.
+  std::string
+  type_descriptor_name(Type*, Named_type*);
+
+  // Return the assembler name for the GC symbol for a type.
+  std::string
+  gc_symbol_name(Type*);
+
+  // Return the assembler name for a ptrmask variable.
+  std::string
+  ptrmask_symbol_name(const std::string& ptrmask_sym_name);
+
+  // Return the name to use for an interface method table.
+  std::string
+  interface_method_table_name(Interface_type*, Type*, bool is_pointer);
+
  private:
   // During parsing, we keep a stack of functions.  Each function on
   // the stack is one that we are currently parsing.  For each
Index: gcc/go/gofrontend/names.cc
===================================================================
--- gcc/go/gofrontend/names.cc	(revision 0)
+++ gcc/go/gofrontend/names.cc	(working copy)
@@ -0,0 +1,825 @@
+// names.cc -- Names used by gofrontend generated code.
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "gogo.h"
+#include "go-encode-id.h"
+#include "types.h"
+#include "expressions.h"
+
+// This file contains functions that generate names that appear in the
+// assembly code.  This is not used for names that appear only in the
+// debug info.
+
+// Return the assembler name to use for an exported function, a
+// method, or a function/method declaration.  This is not called if
+// the function has been given an explicit name via a magic //extern
+// or //go:linkname comment.  GO_NAME is the name that appears in the
+// Go code.  PACKAGE is the package where the function is defined, and
+// is NULL for the package being compiled.  For a method, RTYPE is
+// the method's receiver type; for a function, RTYPE is NULL.
+
+std::string
+Gogo::function_asm_name(const std::string& go_name, const Package* package,
+			const Type* rtype)
+{
+  std::string ret = (package == NULL
+		     ? this->pkgpath_symbol()
+		     : package->pkgpath_symbol());
+
+  if (rtype != NULL
+      && Gogo::is_hidden_name(go_name)
+      && Gogo::hidden_name_pkgpath(go_name) != this->pkgpath())
+    {
+      // This is a method created for an unexported method of an
+      // imported embedded type.  Use the pkgpath of the imported
+      // package.
+      std::string p = Gogo::hidden_name_pkgpath(go_name);
+      ret = this->pkgpath_symbol_for_package(p);
+    }
+
+  ret.append(1, '.');
+  ret.append(Gogo::unpack_hidden_name(go_name));
+
+  if (rtype != NULL)
+    {
+      ret.append(1, '.');
+      ret.append(rtype->mangled_name(this));
+    }
+
+  return go_encode_id(ret);
+}
+
+// Return the assembler name to use for an unexported function.
+// FIXME: This should probably be removed and the callers changed to
+// simply call function_name.
+
+std::string
+Gogo::unexported_function_asm_name(const std::string& go_name)
+{
+  std::string ret = this->package_name();
+  ret.append(1, '.');
+  ret.append(Gogo::unpack_hidden_name(go_name));
+  return go_encode_id(ret);
+}
+
+// Return the name to use for a function descriptor.  These symbols
+// are globally visible.
+
+std::string
+Gogo::function_descriptor_name(Named_object* no)
+{
+  std::string var_name;
+  if (no->is_function_declaration()
+      && !no->func_declaration_value()->asm_name().empty()
+      && Linemap::is_predeclared_location(no->location()))
+    {
+      if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.")
+	var_name = no->func_declaration_value()->asm_name() + "_descriptor";
+      else
+	var_name = no->func_declaration_value()->asm_name() + "$descriptor";
+    }
+  else
+    {
+      if (no->package() == NULL)
+	var_name = this->pkgpath_symbol();
+      else
+	var_name = no->package()->pkgpath_symbol();
+      var_name.push_back('.');
+      var_name.append(Gogo::unpack_hidden_name(no->name()));
+      var_name.append("$descriptor");
+    }
+  return var_name;
+}
+
+// Return the name to use for a generated stub method.  MNAME is the
+// method name.  These functions are globally visible.  Note that this
+// is the function name that corresponds to the name used for the
+// method in Go source code, if this stub method were written in Go.
+// The assembler name will be generated by Gogo::function_asm_name,
+// and because this is a method that name will include the receiver
+// type.
+
+std::string
+Gogo::stub_method_name(const std::string& mname)
+{
+  return mname + "$stub";
+}
+
+// Return the names of the hash and equality functions for TYPE.  If
+// NAME is not NULL it is the name of the type.  Set *HASH_NAME and
+// *EQUAL_NAME.
+
+void
+Gogo::specific_type_function_names(const Type* type, const Named_type* name,
+				   std::string *hash_name,
+				   std::string *equal_name)
+{
+  std::string base_name;
+  if (name == NULL)
+    {
+      // Mangled names can have '.' if they happen to refer to named
+      // types in some way.  That's fine if this is simply a named
+      // type, but otherwise it will confuse the code that builds
+      // function identifiers.  Remove '.' when necessary.
+      base_name = type->mangled_name(this);
+      size_t i;
+      while ((i = base_name.find('.')) != std::string::npos)
+	base_name[i] = '$';
+      base_name = this->pack_hidden_name(base_name, false);
+    }
+  else
+    {
+      // This name is already hidden or not as appropriate.
+      base_name = name->name();
+      unsigned int index;
+      const Named_object* in_function = name->in_function(&index);
+      if (in_function != NULL)
+	{
+	  base_name.append(1, '$');
+	  const Typed_identifier* rcvr =
+	    in_function->func_value()->type()->receiver();
+	  if (rcvr != NULL)
+	    {
+	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+	      base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+	      base_name.append(1, '$');
+	    }
+	  base_name.append(Gogo::unpack_hidden_name(in_function->name()));
+	  if (index > 0)
+	    {
+	      char buf[30];
+	      snprintf(buf, sizeof buf, "%u", index);
+	      base_name += '$';
+	      base_name += buf;
+	    }
+	}
+    }
+  *hash_name = base_name + "$hash";
+  *equal_name = base_name + "$equal";
+}
+
+// Return the assembler name to use for a global variable.  GO_NAME is
+// the name that appears in the Go code.  PACKAGE is the package where
+// the variable is defined, and is NULL for the package being
+// compiled.
+
+std::string
+Gogo::global_var_asm_name(const std::string& go_name, const Package* package)
+{
+  // FIXME: Using package_name for hidden names and pkgpath_symbol for
+  // non-hidden names doesn't make sense, but it dates back to the
+  // first public commit of the gofrontend repo.
+  std::string ret;
+  if (Gogo::is_hidden_name(go_name))
+    ret = (package != NULL
+	   ? package->package_name()
+	   : this->package_name());
+  else
+    ret = (package != NULL
+	   ? package->pkgpath_symbol()
+	   : this->pkgpath_symbol());
+  ret.push_back('.');
+  ret.append(Gogo::unpack_hidden_name(go_name));
+  return go_encode_id(ret);
+}
+
+// Return an erroneous name that indicates that an error has already
+// been reported.
+
+std::string
+Gogo::erroneous_name()
+{
+  static int erroneous_count;
+  char name[50];
+  snprintf(name, sizeof name, "$erroneous%d", erroneous_count);
+  ++erroneous_count;
+  return name;
+}
+
+// Return whether a name is an erroneous name.
+
+bool
+Gogo::is_erroneous_name(const std::string& name)
+{
+  return name.compare(0, 10, "$erroneous") == 0;
+}
+
+// Return a name for a thunk object.
+
+std::string
+Gogo::thunk_name()
+{
+  static int thunk_count;
+  char thunk_name[50];
+  snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
+  ++thunk_count;
+  return thunk_name;
+}
+
+// Return whether a function is a thunk.
+
+bool
+Gogo::is_thunk(const Named_object* no)
+{
+  return no->name().compare(0, 6, "$thunk") == 0;
+}
+
+// Return the name to use for an init function.  There can be multiple
+// functions named "init" so each one needs a different name.
+
+std::string
+Gogo::init_function_name()
+{
+  static int init_count;
+  char buf[30];
+  snprintf(buf, sizeof buf, ".$init%d", init_count);
+  ++init_count;
+  return buf;
+}
+
+// Return the name to use for a nested function.
+
+std::string
+Gogo::nested_function_name()
+{
+  static int nested_count;
+  char buf[30];
+  snprintf(buf, sizeof buf, ".$nested%d", nested_count);
+  ++nested_count;
+  return buf;
+}
+
+// Return the index of a nested function name.
+
+int
+Gogo::nested_function_num(const std::string& name)
+{
+  std::string n(Gogo::unpack_hidden_name(name));
+  go_assert(n.compare(0, 8, ".$nested") == 0);
+  return strtol(n.substr(8).c_str(), NULL, 0);
+}
+
+// Return the name to use for a sink function, a function whose name
+// is simply underscore.  We don't really need these functions but we
+// do have to generate them for error checking.
+
+std::string
+Gogo::sink_function_name()
+{
+  static int sink_count;
+  char buf[30];
+  snprintf(buf, sizeof buf, ".$sink%d", sink_count);
+  ++sink_count;
+  return buf;
+}
+
+// Return the name to use for a redefined function.  These functions
+// are erroneous but we still generate them for further error
+// checking.
+
+std::string
+Gogo::redefined_function_name()
+{
+  static int redefinition_count;
+  char buf[30];
+  snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
+  ++redefinition_count;
+  return buf;
+}
+
+// Return the name to use for a recover thunk for the function NAME.
+// If the function is a method, RTYPE is the receiver type.
+
+std::string
+Gogo::recover_thunk_name(const std::string& name, const Type* rtype)
+{
+  std::string ret(name);
+  if (rtype != NULL)
+    {
+      ret.push_back('$');
+      ret.append(rtype->mangled_name(this));
+    }
+  ret.append("$recover");
+  return ret;
+}
+
+// Return the name to use for a GC root variable.  The GC root
+// variable is a composite literal that is passed to
+// runtime.registerGCRoots.  There is at most one of these variables
+// per compilation.
+
+std::string
+Gogo::gc_root_name()
+{
+  return "gc0";
+}
+
+// Return the name to use for a composite literal or string
+// initializer.  This is a local name never referenced outside of this
+// file.
+
+std::string
+Gogo::initializer_name()
+{
+  static unsigned int counter;
+  char buf[30];
+  snprintf(buf, sizeof buf, "C%u", counter);
+  ++counter;
+  return buf;
+}
+
+// Return the name of the variable used to represent the zero value of
+// a map.  This is a globally visible common symbol.
+
+std::string
+Gogo::map_zero_value_name()
+{
+  return "go$zerovalue";
+}
+
+// Return the name to use for the import control function.
+
+const std::string&
+Gogo::get_init_fn_name()
+{
+  if (this->init_fn_name_.empty())
+    {
+      go_assert(this->package_ != NULL);
+      if (this->is_main_package())
+	{
+	  // Use a name that the runtime knows.
+	  this->init_fn_name_ = "__go_init_main";
+	}
+      else
+	{
+	  std::string s = this->pkgpath_symbol();
+	  s.append("..import");
+	  this->init_fn_name_ = s;
+	}
+    }
+
+  return this->init_fn_name_;
+}
+
+// Return a mangled name for a type.  These names appear in symbol
+// names in the assembler file for things like type descriptors and
+// methods.
+
+std::string
+Type::mangled_name(Gogo* gogo) const
+{
+  std::string ret;
+
+  // The do_mangled_name virtual function should set RET to the
+  // mangled name.  For a composite type it should append a code for
+  // the composition and then call do_mangled_name on the components.
+  this->do_mangled_name(gogo, &ret);
+
+  return ret;
+}
+
+// The mangled name is implemented as a method on each instance of
+// Type.
+
+void
+Error_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('E');
+}
+
+void
+Void_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('v');
+}
+
+void
+Boolean_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('b');
+}
+
+void
+Integer_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "i%s%s%de",
+	   this->is_abstract_ ? "a" : "",
+	   this->is_unsigned_ ? "u" : "",
+	   this->bits_);
+  ret->append(buf);
+}
+
+void
+Float_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "f%s%de",
+	   this->is_abstract_ ? "a" : "",
+	   this->bits_);
+  ret->append(buf);
+}
+
+void
+Complex_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "c%s%de",
+	   this->is_abstract_ ? "a" : "",
+	   this->bits_);
+  ret->append(buf);
+}
+
+void
+String_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('z');
+}
+
+void
+Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('F');
+
+  if (this->receiver_ != NULL)
+    {
+      ret->push_back('m');
+      this->append_mangled_name(this->receiver_->type(), gogo, ret);
+    }
+
+  const Typed_identifier_list* params = this->parameters();
+  if (params != NULL)
+    {
+      ret->push_back('p');
+      for (Typed_identifier_list::const_iterator p = params->begin();
+	   p != params->end();
+	   ++p)
+	this->append_mangled_name(p->type(), gogo, ret);
+      if (this->is_varargs_)
+	ret->push_back('V');
+      ret->push_back('e');
+    }
+
+  const Typed_identifier_list* results = this->results();
+  if (results != NULL)
+    {
+      ret->push_back('r');
+      for (Typed_identifier_list::const_iterator p = results->begin();
+	   p != results->end();
+	   ++p)
+	this->append_mangled_name(p->type(), gogo, ret);
+      ret->push_back('e');
+    }
+
+  ret->push_back('e');
+}
+
+void
+Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('p');
+  this->append_mangled_name(this->to_type_, gogo, ret);
+}
+
+void
+Nil_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('n');
+}
+
+void
+Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('S');
+
+  const Struct_field_list* fields = this->fields_;
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator p = fields->begin();
+	   p != fields->end();
+	   ++p)
+	{
+	  if (p->is_anonymous())
+	    ret->append("0_");
+	  else
+            {
+
+              std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
+	      char buf[20];
+	      snprintf(buf, sizeof buf, "%u_",
+		       static_cast<unsigned int>(n.length()));
+	      ret->append(buf);
+	      ret->append(n);
+	    }
+
+	  // For an anonymous field with an alias type, the field name
+	  // is the alias name.
+	  if (p->is_anonymous()
+	      && p->type()->named_type() != NULL
+	      && p->type()->named_type()->is_alias())
+	    p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
+	  else
+	    this->append_mangled_name(p->type(), gogo, ret);
+	  if (p->has_tag())
+	    {
+	      const std::string& tag(p->tag());
+	      std::string out;
+	      for (std::string::const_iterator p = tag.begin();
+		   p != tag.end();
+		   ++p)
+		{
+		  if (ISALNUM(*p) || *p == '_')
+		    out.push_back(*p);
+		  else
+		    {
+		      char buf[20];
+		      snprintf(buf, sizeof buf, ".%x.",
+			       static_cast<unsigned int>(*p));
+		      out.append(buf);
+		    }
+		}
+	      char buf[20];
+	      snprintf(buf, sizeof buf, "T%u_",
+		       static_cast<unsigned int>(out.length()));
+	      ret->append(buf);
+	      ret->append(out);
+	    }
+	}
+    }
+
+  if (this->is_struct_incomparable_)
+    ret->push_back('x');
+
+  ret->push_back('e');
+}
+
+void
+Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('A');
+  this->append_mangled_name(this->element_type_, gogo, ret);
+  if (this->length_ != NULL)
+    {
+      Numeric_constant nc;
+      if (!this->length_->numeric_constant_value(&nc))
+	{
+	  go_assert(saw_errors());
+	  return;
+	}
+      mpz_t val;
+      if (!nc.to_int(&val))
+	{
+	  go_assert(saw_errors());
+	  return;
+	}
+      char *s = mpz_get_str(NULL, 10, val);
+      ret->append(s);
+      free(s);
+      mpz_clear(val);
+      if (this->is_array_incomparable_)
+	ret->push_back('x');
+    }
+  ret->push_back('e');
+}
+
+void
+Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('M');
+  this->append_mangled_name(this->key_type_, gogo, ret);
+  ret->append("__");
+  this->append_mangled_name(this->val_type_, gogo, ret);
+}
+
+void
+Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('C');
+  this->append_mangled_name(this->element_type_, gogo, ret);
+  if (this->may_send_)
+    ret->push_back('s');
+  if (this->may_receive_)
+    ret->push_back('r');
+  ret->push_back('e');
+}
+
+void
+Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  go_assert(this->methods_are_finalized_);
+
+  ret->push_back('I');
+
+  const Typed_identifier_list* methods = this->all_methods_;
+  if (methods != NULL && !this->seen_)
+    {
+      this->seen_ = true;
+      for (Typed_identifier_list::const_iterator p = methods->begin();
+	   p != methods->end();
+	   ++p)
+	{
+	  if (!p->name().empty())
+	    {
+	      std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
+	      char buf[20];
+	      snprintf(buf, sizeof buf, "%u_",
+		       static_cast<unsigned int>(n.length()));
+	      ret->append(buf);
+	      ret->append(n);
+	    }
+	  this->append_mangled_name(p->type(), gogo, ret);
+	}
+      this->seen_ = false;
+    }
+
+  ret->push_back('e');
+}
+
+void
+Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  this->append_mangled_type_name(gogo, false, ret);
+}
+
+void
+Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  if (this->is_defined())
+    this->append_mangled_name(this->real_type(), gogo, ret);
+  else
+    {
+      const Named_object* no = this->named_object();
+      std::string name;
+      if (no->package() == NULL)
+	name = gogo->pkgpath_symbol();
+      else
+	name = no->package()->pkgpath_symbol();
+      name += '.';
+      name += Gogo::unpack_hidden_name(no->name());
+      char buf[20];
+      snprintf(buf, sizeof buf, "N%u_",
+	       static_cast<unsigned int>(name.length()));
+      ret->append(buf);
+      ret->append(name);
+    }
+}
+
+// Append the mangled name for a named type to RET.  For an alias we
+// normally use the real name, but if USE_ALIAS is true we use the
+// alias name itself.
+
+void
+Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
+				     std::string* ret) const
+{
+  if (this->is_error_)
+    return;
+  if (this->is_alias_ && !use_alias)
+    {
+      if (this->seen_alias_)
+	return;
+      this->seen_alias_ = true;
+      this->append_mangled_name(this->type_, gogo, ret);
+      this->seen_alias_ = false;
+      return;
+    }
+  Named_object* no = this->named_object_;
+  std::string name;
+  if (this->is_builtin())
+    go_assert(this->in_function_ == NULL);
+  else
+    {
+      const std::string& pkgpath(no->package() == NULL
+				 ? gogo->pkgpath_symbol()
+				 : no->package()->pkgpath_symbol());
+      name = pkgpath;
+      name.append(1, '.');
+      if (this->in_function_ != NULL)
+	{
+	  const Typed_identifier* rcvr =
+	    this->in_function_->func_value()->type()->receiver();
+	  if (rcvr != NULL)
+	    {
+	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+	      name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+	      name.append(1, '.');
+	    }
+	  name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
+	  name.append(1, '$');
+	  if (this->in_function_index_ > 0)
+	    {
+	      char buf[30];
+	      snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+	      name.append(buf);
+	      name.append(1, '$');
+	    }
+	}
+    }
+  name.append(Gogo::unpack_hidden_name(no->name()));
+  char buf[20];
+  snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
+  ret->append(buf);
+  ret->append(name);
+}
+
+// Return the name for the type descriptor symbol for TYPE.  This can
+// be a global, common, or local symbol, depending.  NT is not NULL if
+// it is the name to use.
+
+std::string
+Gogo::type_descriptor_name(Type* type, Named_type* nt)
+{
+  // The type descriptor symbol for the unsafe.Pointer type is defined
+  // in libgo/runtime/go-unsafe-pointer.c, so just use a reference to
+  // that symbol.
+  if (type->is_unsafe_pointer_type())
+    return "__go_tdn_unsafe.Pointer";
+
+  if (nt == NULL)
+    return "__go_td_" + type->mangled_name(this);
+
+  Named_object* no = nt->named_object();
+  unsigned int index;
+  const Named_object* in_function = nt->in_function(&index);
+  std::string ret = "__go_tdn_";
+  if (nt->is_builtin())
+    go_assert(in_function == NULL);
+  else
+    {
+      const std::string& pkgpath(no->package() == NULL
+				 ? this->pkgpath_symbol()
+				 : no->package()->pkgpath_symbol());
+      ret.append(pkgpath);
+      ret.append(1, '.');
+      if (in_function != NULL)
+	{
+	  const Typed_identifier* rcvr =
+	    in_function->func_value()->type()->receiver();
+	  if (rcvr != NULL)
+	    {
+	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+	      ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+	      ret.append(1, '.');
+	    }
+	  ret.append(Gogo::unpack_hidden_name(in_function->name()));
+	  ret.append(1, '.');
+	  if (index > 0)
+	    {
+	      char buf[30];
+	      snprintf(buf, sizeof buf, "%u", index);
+	      ret.append(buf);
+	      ret.append(1, '.');
+	    }
+	}
+    }
+
+  std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
+  ret.append(mname);
+
+  return ret;
+}
+
+// Return the name for the GC symbol for a type.  This is used to
+// initialize the gcdata field of a type descriptor.  This is a local
+// name never referenced outside of this assembly file.  (Note that
+// some type descriptors will initialize the gcdata field with a name
+// generated by ptrmask_symbol_name rather than this method.)
+
+std::string
+Gogo::gc_symbol_name(Type* type)
+{
+  return this->type_descriptor_name(type, type->named_type()) + "$gc";
+}
+
+// Return the name for a ptrmask variable.  PTRMASK_SYM_NAME is a
+// base64 string encoding the ptrmask (as returned by Ptrmask::symname
+// in types.cc).  This name is used to intialize the gcdata field of a
+// type descriptor.  These names are globally visible.  (Note that
+// some type descriptors will initialize the gcdata field with a name
+// generated by gc_symbol_name rather than this method.)
+
+std::string
+Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name)
+{
+  return "runtime.gcbits." + ptrmask_sym_name;
+}
+
+// Return the name to use for an interface method table used for the
+// ordinary type TYPE converted to the interface type ITYPE.
+// IS_POINTER is true if this is for the method set for a pointer
+// receiver.
+
+std::string
+Gogo::interface_method_table_name(Interface_type* itype, Type* type,
+				  bool is_pointer)
+{
+  return ((is_pointer ? "__go_pimt__" : "__go_imt_")
+	  + itype->mangled_name(this)
+	  + "__"
+	  + type->mangled_name(this));
+}
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 253311)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -1257,7 +1257,7 @@ Type::make_type_descriptor_var(Gogo* gog
 
       Type* td_type = Type::make_type_descriptor_type();
       Btype* td_btype = td_type->get_backend(gogo);
-      const char *name = "__go_tdn_unsafe.Pointer";
+      std::string name = gogo->type_descriptor_name(this, nt);
       std::string asm_name(go_selectively_encode_id(name));
       this->type_descriptor_var_ =
 	  gogo->backend()->immutable_struct_reference(name, asm_name,
@@ -1269,7 +1269,7 @@ Type::make_type_descriptor_var(Gogo* gog
       return;
     }
 
-  std::string var_name = this->type_descriptor_var_name(gogo, nt);
+  std::string var_name = gogo->type_descriptor_name(this, nt);
 
   // Build the contents of the type descriptor.
   Expression* initializer = this->do_type_descriptor(gogo, NULL);
@@ -1331,56 +1331,6 @@ Type::make_type_descriptor_var(Gogo* gog
 					     binitializer);
 }
 
-// Return the name of the type descriptor variable.  If NT is not
-// NULL, use it to get the name.  Otherwise this is an unnamed type.
-
-std::string
-Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
-{
-  if (nt == NULL)
-    return "__go_td_" + this->mangled_name(gogo);
-
-  Named_object* no = nt->named_object();
-  unsigned int index;
-  const Named_object* in_function = nt->in_function(&index);
-  std::string ret = "__go_tdn_";
-  if (nt->is_builtin())
-    go_assert(in_function == NULL);
-  else
-    {
-      const std::string& pkgpath(no->package() == NULL
-				 ? gogo->pkgpath_symbol()
-				 : no->package()->pkgpath_symbol());
-      ret.append(pkgpath);
-      ret.append(1, '.');
-      if (in_function != NULL)
-	{
-	  const Typed_identifier* rcvr =
-	    in_function->func_value()->type()->receiver();
-	  if (rcvr != NULL)
-	    {
-	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
-	      ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
-	      ret.append(1, '.');
-	    }
-	  ret.append(Gogo::unpack_hidden_name(in_function->name()));
-	  ret.append(1, '.');
-	  if (index > 0)
-	    {
-	      char buf[30];
-	      snprintf(buf, sizeof buf, "%u", index);
-	      ret.append(buf);
-	      ret.append(1, '.');
-	    }
-	}
-    }
-
-  std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
-  ret.append(mname);
-
-  return ret;
-}
-
 // Return true if this type descriptor is defined in a different
 // package.  If this returns true it sets *PACKAGE to the package.
 
@@ -1967,48 +1917,9 @@ Type::specific_type_functions(Gogo* gogo
       return;
     }
 
-  std::string base_name;
-  if (name == NULL)
-    {
-      // Mangled names can have '.' if they happen to refer to named
-      // types in some way.  That's fine if this is simply a named
-      // type, but otherwise it will confuse the code that builds
-      // function identifiers.  Remove '.' when necessary.
-      base_name = this->mangled_name(gogo);
-      size_t i;
-      while ((i = base_name.find('.')) != std::string::npos)
-	base_name[i] = '$';
-      base_name = gogo->pack_hidden_name(base_name, false);
-    }
-  else
-    {
-      // This name is already hidden or not as appropriate.
-      base_name = name->name();
-      unsigned int index;
-      const Named_object* in_function = name->in_function(&index);
-      if (in_function != NULL)
-	{
-	  base_name.append(1, '$');
-	  const Typed_identifier* rcvr =
-	    in_function->func_value()->type()->receiver();
-	  if (rcvr != NULL)
-	    {
-	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
-	      base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
-	      base_name.append(1, '$');
-	    }
-	  base_name.append(Gogo::unpack_hidden_name(in_function->name()));
-	  if (index > 0)
-	    {
-	      char buf[30];
-	      snprintf(buf, sizeof buf, "%u", index);
-	      base_name += '$';
-	      base_name += buf;
-	    }
-	}
-    }
-  std::string hash_name = base_name + "$hash";
-  std::string equal_name = base_name + "$equal";
+  std::string hash_name;
+  std::string equal_name;
+  gogo->specific_type_function_names(this, name, &hash_name, &equal_name);
 
   Location bloc = Linemap::predeclared_location();
 
@@ -2525,7 +2436,7 @@ Type::make_gc_symbol_var(Gogo* gogo)
       return;
     }
 
-  std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
+  std::string sym_name = gogo->gc_symbol_name(this);
 
   // Build the contents of the gc symbol.
   Expression* sym_init = this->gcprog_constructor(gogo, ptrsize, ptrdata);
@@ -2818,7 +2729,8 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t
       // This can happen in error cases.  Just build an empty gcbits.
       go_assert(saw_errors());
     }
-  std::string sym_name = "runtime.gcbits." + ptrmask.symname();
+
+  std::string sym_name = gogo->ptrmask_symbol_name(ptrmask.symname());
   Bvariable* bvnull = NULL;
   std::pair<GC_gcbits_vars::iterator, bool> ins =
     Type::gc_gcbits_vars.insert(std::make_pair(sym_name, bvnull));
@@ -3462,21 +3374,6 @@ Type::reflection(Gogo* gogo) const
   return ret;
 }
 
-// Return a mangled name for the type.
-
-std::string
-Type::mangled_name(Gogo* gogo) const
-{
-  std::string ret;
-
-  // The do_mangled_name virtual function should set RET to the
-  // mangled name.  For a composite type it should append a code for
-  // the composition and then call do_mangled_name on the components.
-  this->do_mangled_name(gogo, &ret);
-
-  return ret;
-}
-
 // Return whether the backend size of the type is known.
 
 bool
@@ -3796,37 +3693,32 @@ Type::import_type(Import* imp)
     }
 }
 
-// A type used to indicate a parsing error.  This exists to simplify
-// later error detection.
+// Class Error_type.
+
+// Return the backend representation of an Error type.
 
-class Error_type : public Type
+Btype*
+Error_type::do_get_backend(Gogo* gogo)
 {
- public:
-  Error_type()
-    : Type(TYPE_ERROR)
-  { }
+  return gogo->backend()->error_type();
+}
 
- protected:
-  bool
-  do_compare_is_identity(Gogo*)
-  { return false; }
+// Return an expression for the type descriptor for an error type.
 
-  Btype*
-  do_get_backend(Gogo* gogo)
-  { return gogo->backend()->error_type(); }
 
-  Expression*
-  do_type_descriptor(Gogo*, Named_type*)
-  { return Expression::make_error(Linemap::predeclared_location()); }
+Expression*
+Error_type::do_type_descriptor(Gogo*, Named_type*)
+{
+  return Expression::make_error(Linemap::predeclared_location());
+}
 
-  void
-  do_reflection(Gogo*, std::string*) const
-  { go_assert(saw_errors()); }
+// We should not be asked for the reflection string for an error type.
 
-  void
-  do_mangled_name(Gogo*, std::string* ret) const
-  { ret->push_back('E'); }
-};
+void
+Error_type::do_reflection(Gogo*, std::string*) const
+{
+  go_assert(saw_errors());
+}
 
 Type*
 Type::make_error_type()
@@ -3835,36 +3727,15 @@ Type::make_error_type()
   return &singleton_error_type;
 }
 
-// The void type.
-
-class Void_type : public Type
-{
- public:
-  Void_type()
-    : Type(TYPE_VOID)
-  { }
-
- protected:
-  bool
-  do_compare_is_identity(Gogo*)
-  { return false; }
-
-  Btype*
-  do_get_backend(Gogo* gogo)
-  { return gogo->backend()->void_type(); }
-
-  Expression*
-  do_type_descriptor(Gogo*, Named_type*)
-  { go_unreachable(); }
+// Class Void_type.
 
-  void
-  do_reflection(Gogo*, std::string*) const
-  { }
+// Get the backend representation of a void type.
 
-  void
-  do_mangled_name(Gogo*, std::string* ret) const
-  { ret->push_back('v'); }
-};
+Btype*
+Void_type::do_get_backend(Gogo* gogo)
+{
+  return gogo->backend()->void_type();
+}
 
 Type*
 Type::make_void_type()
@@ -3873,36 +3744,15 @@ Type::make_void_type()
   return &singleton_void_type;
 }
 
-// The boolean type.
-
-class Boolean_type : public Type
-{
- public:
-  Boolean_type()
-    : Type(TYPE_BOOLEAN)
-  { }
+// Class Boolean_type.
 
- protected:
-  bool
-  do_compare_is_identity(Gogo*)
-  { return true; }
+// Return the backend representation of the boolean type.
 
-  Btype*
-  do_get_backend(Gogo* gogo)
-  { return gogo->backend()->bool_type(); }
-
-  Expression*
-  do_type_descriptor(Gogo*, Named_type* name);
-
-  // We should not be asked for the reflection string of a basic type.
-  void
-  do_reflection(Gogo*, std::string* ret) const
-  { ret->append("bool"); }
-
-  void
-  do_mangled_name(Gogo*, std::string* ret) const
-  { ret->push_back('b'); }
-};
+Btype*
+Boolean_type::do_get_backend(Gogo* gogo)
+{
+  return gogo->backend()->bool_type();
+}
 
 // Make the type descriptor.
 
@@ -4069,19 +3919,6 @@ Integer_type::do_reflection(Gogo*, std::
   go_assert(saw_errors());
 }
 
-// Mangled name.
-
-void
-Integer_type::do_mangled_name(Gogo*, std::string* ret) const
-{
-  char buf[100];
-  snprintf(buf, sizeof buf, "i%s%s%de",
-	   this->is_abstract_ ? "a" : "",
-	   this->is_unsigned_ ? "u" : "",
-	   this->bits_);
-  ret->append(buf);
-}
-
 // Make an integer type.
 
 Named_type*
@@ -4204,18 +4041,6 @@ Float_type::do_reflection(Gogo*, std::st
   go_assert(saw_errors());
 }
 
-// Mangled name.
-
-void
-Float_type::do_mangled_name(Gogo*, std::string* ret) const
-{
-  char buf[100];
-  snprintf(buf, sizeof buf, "f%s%de",
-	   this->is_abstract_ ? "a" : "",
-	   this->bits_);
-  ret->append(buf);
-}
-
 // Make a floating point type.
 
 Named_type*
@@ -4331,18 +4156,6 @@ Complex_type::do_reflection(Gogo*, std::
   go_assert(saw_errors());
 }
 
-// Mangled name.
-
-void
-Complex_type::do_mangled_name(Gogo*, std::string* ret) const
-{
-  char buf[100];
-  snprintf(buf, sizeof buf, "c%s%de",
-	   this->is_abstract_ ? "a" : "",
-	   this->bits_);
-  ret->append(buf);
-}
-
 // Make a complex type.
 
 Named_type*
@@ -4428,14 +4241,6 @@ String_type::do_reflection(Gogo*, std::s
   ret->append("string");
 }
 
-// Mangled name of a string type.
-
-void
-String_type::do_mangled_name(Gogo*, std::string* ret) const
-{
-  ret->push_back('z');
-}
-
 // Make a string type.
 
 Type*
@@ -5082,46 +4887,6 @@ Function_type::do_reflection(Gogo* gogo,
     }
 }
 
-// Mangled name.
-
-void
-Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('F');
-
-  if (this->receiver_ != NULL)
-    {
-      ret->push_back('m');
-      this->append_mangled_name(this->receiver_->type(), gogo, ret);
-    }
-
-  const Typed_identifier_list* params = this->parameters();
-  if (params != NULL)
-    {
-      ret->push_back('p');
-      for (Typed_identifier_list::const_iterator p = params->begin();
-	   p != params->end();
-	   ++p)
-	this->append_mangled_name(p->type(), gogo, ret);
-      if (this->is_varargs_)
-	ret->push_back('V');
-      ret->push_back('e');
-    }
-
-  const Typed_identifier_list* results = this->results();
-  if (results != NULL)
-    {
-      ret->push_back('r');
-      for (Typed_identifier_list::const_iterator p = results->begin();
-	   p != results->end();
-	   ++p)
-	this->append_mangled_name(p->type(), gogo, ret);
-      ret->push_back('e');
-    }
-
-  ret->push_back('e');
-}
-
 // Export a function type.
 
 void
@@ -5484,13 +5249,6 @@ Pointer_type::do_reflection(Gogo* gogo,
   this->append_reflection(this->to_type_, gogo, ret);
 }
 
-void
-Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('p');
-  this->append_mangled_name(this->to_type_, gogo, ret);
-}
-
 // Export.
 
 void
@@ -5572,38 +5330,16 @@ Type::finish_pointer_types(Gogo* gogo)
     }
 }
 
-// The nil type.  We use a special type for nil because it is not the
-// same as any other type.  In C term nil has type void*, but there is
-// no such type in Go.
-
-class Nil_type : public Type
-{
- public:
-  Nil_type()
-    : Type(TYPE_NIL)
-  { }
-
- protected:
-  bool
-  do_compare_is_identity(Gogo*)
-  { return false; }
-
-  Btype*
-  do_get_backend(Gogo* gogo)
-  { return gogo->backend()->pointer_type(gogo->backend()->void_type()); }
+// Class Nil_type.
 
-  Expression*
-  do_type_descriptor(Gogo*, Named_type*)
-  { go_unreachable(); }
+// Get the backend representation of a nil type.  FIXME: Is this ever
+// actually called?
 
-  void
-  do_reflection(Gogo*, std::string*) const
-  { go_unreachable(); }
-
-  void
-  do_mangled_name(Gogo*, std::string* ret) const
-  { ret->push_back('n'); }
-};
+Btype*
+Nil_type::do_get_backend(Gogo* gogo)
+{
+  return gogo->backend()->pointer_type(gogo->backend()->void_type());
+}
 
 // Make the nil type.
 
@@ -6692,74 +6428,6 @@ Struct_type::do_reflection(Gogo* gogo, s
   ret->push_back('}');
 }
 
-// Mangled name.
-
-void
-Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('S');
-
-  const Struct_field_list* fields = this->fields_;
-  if (fields != NULL)
-    {
-      for (Struct_field_list::const_iterator p = fields->begin();
-	   p != fields->end();
-	   ++p)
-	{
-	  if (p->is_anonymous())
-	    ret->append("0_");
-	  else
-            {
-
-              std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
-	      char buf[20];
-	      snprintf(buf, sizeof buf, "%u_",
-		       static_cast<unsigned int>(n.length()));
-	      ret->append(buf);
-	      ret->append(n);
-	    }
-
-	  // For an anonymous field with an alias type, the field name
-	  // is the alias name.
-	  if (p->is_anonymous()
-	      && p->type()->named_type() != NULL
-	      && p->type()->named_type()->is_alias())
-	    p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
-	  else
-	    this->append_mangled_name(p->type(), gogo, ret);
-	  if (p->has_tag())
-	    {
-	      const std::string& tag(p->tag());
-	      std::string out;
-	      for (std::string::const_iterator p = tag.begin();
-		   p != tag.end();
-		   ++p)
-		{
-		  if (ISALNUM(*p) || *p == '_')
-		    out.push_back(*p);
-		  else
-		    {
-		      char buf[20];
-		      snprintf(buf, sizeof buf, ".%x.",
-			       static_cast<unsigned int>(*p));
-		      out.append(buf);
-		    }
-		}
-	      char buf[20];
-	      snprintf(buf, sizeof buf, "T%u_",
-		       static_cast<unsigned int>(out.length()));
-	      ret->append(buf);
-	      ret->append(out);
-	    }
-	}
-    }
-
-  if (this->is_struct_incomparable_)
-    ret->push_back('x');
-
-  ret->push_back('e');
-}
-
 // If the offset of field INDEX in the backend implementation can be
 // determined, set *POFFSET to the offset in bytes and return true.
 // Otherwise, return false.
@@ -7951,37 +7619,6 @@ Array_type::do_reflection(Gogo* gogo, st
   this->append_reflection(this->element_type_, gogo, ret);
 }
 
-// Mangled name.
-
-void
-Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('A');
-  this->append_mangled_name(this->element_type_, gogo, ret);
-  if (this->length_ != NULL)
-    {
-      Numeric_constant nc;
-      if (!this->length_->numeric_constant_value(&nc))
-	{
-	  go_assert(saw_errors());
-	  return;
-	}
-      mpz_t val;
-      if (!nc.to_int(&val))
-	{
-	  go_assert(saw_errors());
-	  return;
-	}
-      char *s = mpz_get_str(NULL, 10, val);
-      ret->append(s);
-      free(s);
-      mpz_clear(val);
-      if (this->is_array_incomparable_)
-	ret->push_back('x');
-    }
-  ret->push_back('e');
-}
-
 // Make an array type.
 
 Array_type*
@@ -8037,8 +7674,8 @@ Map_type::fat_zero_value(Gogo* gogo)
       Array_type* array_type = Type::make_array_type(uint8_type, size);
       array_type->set_is_array_incomparable();
       Variable* var = new Variable(array_type, NULL, true, false, false, bloc);
-      Map_type::zero_value = Named_object::make_variable("go$zerovalue", NULL,
-							 var);
+      std::string name = gogo->map_zero_value_name();
+      Map_type::zero_value = Named_object::make_variable(name, NULL, var);
     }
 
   Expression* z = Expression::make_var_reference(Map_type::zero_value, bloc);
@@ -8582,17 +8219,6 @@ Map_type::do_reflection(Gogo* gogo, std:
   this->append_reflection(this->val_type_, gogo, ret);
 }
 
-// Mangled name for a map.
-
-void
-Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('M');
-  this->append_mangled_name(this->key_type_, gogo, ret);
-  ret->append("__");
-  this->append_mangled_name(this->val_type_, gogo, ret);
-}
-
 // Export a map type.
 
 void
@@ -8765,20 +8391,6 @@ Channel_type::do_reflection(Gogo* gogo,
   this->append_reflection(this->element_type_, gogo, ret);
 }
 
-// Mangled name.
-
-void
-Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  ret->push_back('C');
-  this->append_mangled_name(this->element_type_, gogo, ret);
-  if (this->may_send_)
-    ret->push_back('s');
-  if (this->may_receive_)
-    ret->push_back('r');
-  ret->push_back('e');
-}
-
 // Export.
 
 void
@@ -9702,40 +9314,6 @@ Interface_type::do_reflection(Gogo* gogo
   ret->append("}");
 }
 
-// Mangled name.
-
-void
-Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  go_assert(this->methods_are_finalized_);
-
-  ret->push_back('I');
-
-  const Typed_identifier_list* methods = this->all_methods_;
-  if (methods != NULL && !this->seen_)
-    {
-      this->seen_ = true;
-      for (Typed_identifier_list::const_iterator p = methods->begin();
-	   p != methods->end();
-	   ++p)
-	{
-	  if (!p->name().empty())
-	    {
-	      std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
-	      char buf[20];
-	      snprintf(buf, sizeof buf, "%u_",
-		       static_cast<unsigned int>(n.length()));
-	      ret->append(buf);
-	      ret->append(n);
-	    }
-	  this->append_mangled_name(p->type(), gogo, ret);
-	}
-      this->seen_ = false;
-    }
-
-  ret->push_back('e');
-}
-
 // Export.
 
 void
@@ -11178,71 +10756,6 @@ Named_type::append_reflection_type_name(
   ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
 }
 
-// Get the mangled name.
-
-void
-Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  this->append_mangled_type_name(gogo, false, ret);
-}
-
-// Get the mangled name.  For an alias we normally get the real name,
-// but if USE_ALIAS is true we use the alias name itself.
-
-void
-Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
-				     std::string* ret) const
-{
-  if (this->is_error_)
-    return;
-  if (this->is_alias_ && !use_alias)
-    {
-      if (this->seen_alias_)
-	return;
-      this->seen_alias_ = true;
-      this->append_mangled_name(this->type_, gogo, ret);
-      this->seen_alias_ = false;
-      return;
-    }
-  Named_object* no = this->named_object_;
-  std::string name;
-  if (this->is_builtin())
-    go_assert(this->in_function_ == NULL);
-  else
-    {
-      const std::string& pkgpath(no->package() == NULL
-				 ? gogo->pkgpath_symbol()
-				 : no->package()->pkgpath_symbol());
-      name = pkgpath;
-      name.append(1, '.');
-      if (this->in_function_ != NULL)
-	{
-	  const Typed_identifier* rcvr =
-	    this->in_function_->func_value()->type()->receiver();
-	  if (rcvr != NULL)
-	    {
-	      Named_type* rcvr_type = rcvr->type()->deref()->named_type();
-	      name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
-	      name.append(1, '.');
-	    }
-	  name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
-	  name.append(1, '$');
-	  if (this->in_function_index_ > 0)
-	    {
-	      char buf[30];
-	      snprintf(buf, sizeof buf, "%u", this->in_function_index_);
-	      name.append(buf);
-	      name.append(1, '$');
-	    }
-	}
-    }
-  name.append(Gogo::unpack_hidden_name(no->name()));
-  char buf[20];
-  snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
-  ret->append(buf);
-  ret->append(name);
-}
-
 // Export the type.  This is called to export a global type.
 
 void
@@ -11623,7 +11136,7 @@ Type::build_stub_methods(Gogo* gogo, con
 	package = NULL;
       else
 	package = type->named_type()->named_object()->package();
-      std::string stub_name = name + "$stub";
+      std::string stub_name = gogo->stub_method_name(name);
       Named_object* stub;
       if (package != NULL)
 	stub = Named_object::make_function_declaration(stub_name, package,
@@ -12453,31 +11966,6 @@ Forward_declaration_type::do_reflection(
   this->append_reflection(this->real_type(), gogo, ret);
 }
 
-// The mangled name.
-
-void
-Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
-  if (this->is_defined())
-    this->append_mangled_name(this->real_type(), gogo, ret);
-  else
-    {
-      const Named_object* no = this->named_object();
-      std::string name;
-      if (no->package() == NULL)
-	name = gogo->pkgpath_symbol();
-      else
-	name = no->package()->pkgpath_symbol();
-      name += '.';
-      name += Gogo::unpack_hidden_name(no->name());
-      char buf[20];
-      snprintf(buf, sizeof buf, "N%u_",
-	       static_cast<unsigned int>(name.length()));
-      ret->append(buf);
-      ret->append(name);
-    }
-}
-
 // Export a forward declaration.  This can happen when a defined type
 // refers to a type which is only declared (and is presumably defined
 // in some other file in the same package).
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 253311)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -1213,11 +1213,6 @@ class Type
   void
   make_gc_symbol_var(Gogo*);
 
-  // Return the name of the type descriptor variable.  If NAME is not
-  // NULL, it is the name to use.
-  std::string
-  type_descriptor_var_name(Gogo*, Named_type* name);
-
   // Return true if the type descriptor for this type should be
   // defined in some other package.  If NAME is not NULL, it is the
   // name of this type.  If this returns true it sets *PACKAGE to the
@@ -1558,6 +1553,92 @@ class Typed_identifier_list
   std::vector<Typed_identifier> entries_;
 };
 
+// A type used to indicate a parsing error.  This exists to simplify
+// later error detection.
+
+class Error_type : public Type
+{
+ public:
+  Error_type()
+    : Type(TYPE_ERROR)
+  { }
+
+ protected:
+  bool
+  do_compare_is_identity(Gogo*)
+  { return false; }
+
+  Btype*
+  do_get_backend(Gogo* gogo);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+};
+
+// The void type.
+
+class Void_type : public Type
+{
+ public:
+  Void_type()
+    : Type(TYPE_VOID)
+  { }
+
+ protected:
+  bool
+  do_compare_is_identity(Gogo*)
+  { return false; }
+
+  Btype*
+  do_get_backend(Gogo* gogo);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { go_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+};
+
+// The boolean type.
+
+class Boolean_type : public Type
+{
+ public:
+  Boolean_type()
+    : Type(TYPE_BOOLEAN)
+  { }
+
+ protected:
+  bool
+  do_compare_is_identity(Gogo*)
+  { return true; }
+
+  Btype*
+  do_get_backend(Gogo* gogo);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type* name);
+
+  // We should not be asked for the reflection string of a basic type.
+  void
+  do_reflection(Gogo*, std::string* ret) const
+  { ret->append("bool"); }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+};
+
 // The type of an integer.
 
 class Integer_type : public Type
@@ -2143,6 +2224,37 @@ class Pointer_type : public Type
   Type* to_type_;
 };
 
+// The nil type.  We use a special type for nil because it is not the
+// same as any other type.  In C term nil has type void*, but there is
+// no such type in Go.
+
+class Nil_type : public Type
+{
+ public:
+  Nil_type()
+    : Type(TYPE_NIL)
+  { }
+
+ protected:
+  bool
+  do_compare_is_identity(Gogo*)
+  { return false; }
+
+  Btype*
+  do_get_backend(Gogo* gogo);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { go_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { go_unreachable(); }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+};
+
 // The type of a field in a struct.
 
 class Struct_field
