Go patch committed: Consolidate all names in one place

Ian Lance Taylor iant@golang.org
Thu Oct 5 17:20:00 GMT 2017


This patch to the Go frontend consolidates all external name handling
in one place: a new file names.cc.  This handles names that might
appear in the assembly code, not necessarily names that are only used
for local variables and labels and the like.

This patch does not change any of the names, it just puts all the name
code in one place.  I checked that none of the symbol names in libgo
changed when this patch was used.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

2017-10-05  Ian Lance Taylor  <iant@golang.org>

* Make-lang.in (GO_OBJS): Add go/names.o.
-------------- next part --------------
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


More information about the Gcc-patches mailing list