(root)/
gcc-13.2.0/
gcc/
go/
gofrontend/
names.cc
// 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.

// Our external names may contain only ASCII alphanumeric characters,
// underscore, and dot.  (According to the GCC sources, dot is not
// permitted in assembler symbols on VxWorks and MMIX.  We will not
// support those systems.)  Go identifiers cannot contain dot, but Go
// package paths can.  Both Go identifiers and package paths can, of
// course, contain all sorts of Unicode characters.
//
// The gc compiler uses names like "pkg.F", and it seems convenient to
// emulate that.  Therefore, we will use dot to separate different
// components of names.
//
// Since package paths can contain dot, to avoid ambiguity we must
// encode package paths such that they do not contain any dot.  The
// natural way to do this is to encode forbidden characters, including
// dot, using a notation based on underscore.  We will, of course,
// have to encode underscore itself.
//
// Since we will be using an underscore encoding for the package path,
// it seems reasonable to use the same encoding for Go identifiers.
// This has the disadvantage that encoded Go identifiers will appear
// to be valid Go identifiers with funny spellings, but it seems like
// the best available approach.
//
// Therefore, in the following discussion we may assume that none of
// the names under discussion contain a dot.  All of the names we
// generate for Go identifiers (that don't use //export or
// //go:linkname) will contain at least one dot, as discussed below.
// We assume that none of the non-Go symbols in the final link will
// contain a dot, so we don't worry about conflicts.
//
// We first describe the basic symbol names, used to represent Go
// functions and variables.
//
// The external name for a normal Go symbol NAME, a function or
// variable, is simply "PKGPATH.NAME".  Note that NAME is not the
// packed form used for the "hidden" name internally in the compiler;
// it is the name that appears in the source code.  Both PKGPATH and
// NAME will be encoded as described below.  The encoding process
// ensures that neither encoded string can contain a dot, and neither
// will start with a digit (NAME is a Go identifier that can't contain
// a dot or start with a digit anyhow).  The encoding process means
// that these external names contain exactly one dot and do not start
// with a dot.
//
// The external name for a method NAME for a named type TYPE is
// "PKGPATH.TYPE.NAME".  Both NAME and TYPE are simple Go identifiers.
// Unlike the gc compiler, the external name does not indicate whether
// this is a pointer method or a value method; a named type can not
// have both a pointer and value method with the same name, so there
// is no ambiguity.  PKGPATH is the package path of the package in
// which TYPE is defined.  PKGPATH, TYPE, and NAME are encoded, and
// cannot be empty or contain a dot or start with a digit.  These
// external names contain exactly two dots, not consecutive, and they
// do not start with a dot.
//
// It's uncommon, but the use of type literals with embedded fields
// can cause us to have methods on unnamed types.  The external names
// for these are also PKGPATH.TYPELIT.NAME, where TYPELIT is an
// approximately readable version of the type literal, described
// below.  A TYPELIT will always contain characters that cannot appear
// in a Go identifier, so TYPELIT can never be confused with a TYPE
// name.  There is no ambiguity as long as encoded type literals are
// unambiguous.
//
// Also uncommon is an external name that must refer to a named type
// defined within a function.  While such a type can not have methods
// itself, it can pick up embedded methods, and those methods need
// names.  These are treated as a kind of type literal written as,
// before type literal encoding, FNNAME.TYPENAME(INDEX) or, for a
// method, TYPE.MNAME.TYPENAME(INDEX).  INDEX is the index of that
// named type within the function, as a single function can have
// multiple types with the same name.  This is unambiguous as
// parentheses can not appear in a type literal in this form (they can
// only appear in interface method declarations).
//
// That is the end of the list of basic names.  The remaining names
// exist for special purposes, and are differentiated from the basic
// names by containing two consecutive dots.
//
// The hash function for a type is treated as a method whose name is
// ".hash".  That is, the method name begins with a dot.  The effect
// is that there will be two consecutive dots in the name; the name
// will always end with "..hash".
//
// Similarly the equality function for a type is treated as a method
// whose name is ".eq".
//
// The function descriptor for a function is the same as the name of
// the function with an added suffix "..f".
//
// A thunk for a go or defer statement is treated as a function whose
// name is ".thunkNN", unencoded, where NN is a sequence of digits
// (these functions are never globally visible).  Thus the final name
// of a thunk will be PKGPATH..thunkNN (PKGPATH is encoded).
//
// An init function is treated as a function whose name is ".initNN",
// unencoded, where NN is a sequence of digits (these functions are
// never globally visible).  Thus the final name of an init function
// will be PKGPATH..initNN (PKGPATH is encoded).
//
// A nested function is given the name of outermost enclosing function
// or method with an added suffix "..funcNN", unencoded, where NN is a
// sequence of digits.  Note that the function descriptor of a nested
// function, if needed, will end with "..funcNN..f".
//
// A recover thunk is the same as the name of the function with an
// added suffix "..r".
//
// The name of a type descriptor for a named type is
// PKGPATH.TYPENAME..d (PKGPATH and TYPENAME are encoded).
//
// The name of a type descriptor for a pointer to a named type is
// PKGPATH.TYPENAME..p (PKGPATH and TYPENAME are encoded).
//
// The name of a type descriptor for an unnamed type is type..TYPELIT.
// That is, the string "type.." followed by the encoded type literal.
// These names are common symbols, in the linker's sense of the word
// common: in the final executable there is only one instance of the
// type descriptor for a given unnamed type.
//
// The name of the GC symbol for a named type is PKGPATH.TYPE..g
// (PKGPATH and TYPE are encoded).
//
// The name of the GC symbol for an unnamed type is type..TYPELIT..g.
// These are common symbols.
//
// The name of a ptrmask symbol is gcbits..B32 where B32 is an
// encoding of the ptrmask bits using only ASCII letters.  These are
// common symbols.
//
// An interface method table for assigning the non-interface type TYPE
// to the interface type ITYPE is named imt..ITYPE..TYPE.  If ITYPE or
// TYPE is a named type, they are written as PKGPATH.TYPE (where both
// PKGPATH and TYPE are encoded).  Otherwise they are written as a
// type literal.  An interface method table for a pointer method set
// uses pimt instead of imt.
//
// The names of composite literal initializers, including the GC root
// variable, are not referenced.  They must not conflict with any C
// language names, but the names are otherwise unimportant.  They are
// named "go..CNN" where NN is a sequence of digits.  The names do not
// include the PKGPATH.
//
// The map zero value, a common symbol that represents the zero value
// of a map, is named simply "go..zerovalue".  The name does not
// include the PKGPATH.
//
// The import function for the main package is referenced by C code,
// and is named __go_init_main.  For other packages it is
// PKGPATH..import.  If a package doesn't need an init function, it
// will have a dummy one, named ~PKGPATH.
//
// In each package there is a list of all the type descriptors defined
// in this package.  The name of the list is PKGPATH..types.
//
// In the main package it gathers all the type descriptor lists in a
// single list, named go..typelists.
//
// The type literal encoding is essentially a single line version of
// the type literal, such as "struct { pkgpath.i int; J int }".  In
// this representation unexported names use their pkgpath, exported
// names omit it.
//
// The type literal encoding is not quite valid Go, as some aspects of
// compiler generated types can not be represented.  For example,
// incomparable struct types have an extra field "{x}".  Struct tags
// can contain any character, which will be underscore encoded as
// usual.  In the unusual case of a curly brace or a backslash in a
// struct tag, the brace or backslash will be backslash quoted, before
// underscore encoding.
//
// Many of these names will be visible in the debugger.  The debugger
// will be given these names before applying any underscore encoding.
// These user names do not have to be unique--they are only used by
// the debugger, not the linker--so this is OK.  However, there is an
// exception: if the name would otherwise include characters that
// can't normally appear in an identifier, then the user name will
// also be underscore encoded.  This avoids problems with
// communicating the debug info to the assembler and with handling the
// debug info in the debugger.  A Go-aware debugger will need to know
// whether to apply underscore decoding to a name before showing it to
// the user.  We indicate this by adding a prefix of "g.", and
// assuming that cases of a package path of "g" are unusual.  This
// prefix will only appear in the user name, not the assembler name.
//
// The underscore encoding is, naturally, an underscore followed by
// other characters.  As there are various characters that commonly
// appear in type literals and in package paths, we have a set of
// short encodings.  Then we have general encodings for other
// characters.
//
//   __ - '_'
//   _0 - '.'
//   _1 - '/'
//   _2 - '*'
//   _3 - ','
//   _4 - '{'
//   _5 - '}'
//   _6 - '['
//   _7 - ']'
//   _8 - '('
//   _9 - ')'
//   _a - '"'
//   _b - ' '
//   _c - ';'
//
// Other non-alphanumeric ASCII characters are encoded as _xNN, where
// NN is the hex value for the character.  If an encoded name would
// otherwise start with a digit, this encoding is also used for the
// leading digit.
//
// Non-ASCII Unicode characters are encoded as _u and four hex digits
// or _U and eight digits, just as in the language only using _u and
// _U instead of \u and \U.
//
// Demangling these names is straightforward:
//  - replace _xXX with an ASCII character
//  - replace _uXXXX with a unicode character
//  - replace _UXXXXXXXX with a unicode character
//  - replace _C per the table above
// That will get you as close as possible to a readable name.

// Set BNAME to the name to use for an exported function, a method, or
// a function/method declaration.  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.

void
Gogo::function_backend_name(const std::string& go_name,
			    const Package* package, const Type* rtype,
			    Backend_name* bname)
{
  if (rtype != NULL)
    rtype->deref()->backend_name(this, bname);
  else if (package == NULL)
    bname->add(this->pkgpath());
  else
    bname->add(package->pkgpath());

  size_t pos = Gogo::special_name_pos(go_name);
  if (pos == std::string::npos)
    bname->add(Gogo::unpack_hidden_name(go_name));
  else
    {
      if (pos > 0)
	bname->add(go_name.substr(0, pos));
      bname->set_suffix(go_name.substr(pos));
    }
}

// Set BNAME to the name to use for a function descriptor.  These
// symbols are globally visible.

void
Gogo::function_descriptor_backend_name(Named_object* no,
				       Backend_name* bname)
{
  if (no->is_function())
    no->func_value()->backend_name(this, no, bname);
  else if (no->is_function_declaration())
    no->func_declaration_value()->backend_name(this, no, bname);
  else
    go_unreachable();
  bname->append_suffix("..f");
}

// Return the name to use for a generated stub method.  A stub method
// is used as the method table entry for a promoted method of an
// embedded type.  MNAME is the method name.  PACKAGE is the package
// where the type that needs this stub method is defined.  These
// functions are globally visible.
//
// This returns a name that acts like a Go identifier, as though the
// stub method were written in Go as an explicitly defined method that
// simply calls the promoted method.  The name we return here will
// eventually be passed to function_backend_name, which will return a
// name that includes the receiver type.
//
// We construct a unique method name and append "..stub".
// function_backend_name will look for the "..stub" and turn that into
// an unencoded suffix.  The rest of the name will be encoded as
// usual.

std::string
Gogo::stub_method_name(const Package* package, const std::string& mname)
{
  if (!Gogo::is_hidden_name(mname))
    return mname + "..stub";

  const std::string& ppkgpath(package == NULL
			      ? this->pkgpath()
			      : package->pkgpath());
  std::string mpkgpath = Gogo::hidden_name_pkgpath(mname);
  if (mpkgpath == ppkgpath)
    return Gogo::unpack_hidden_name(mname) + "..stub";

  // We are creating a stub method for an unexported method of an
  // imported embedded type.  A single type can have multiple promoted
  // methods with the same unexported name, if it embeds types from
  // different packages.  We need to disambiguate the method name.
  // This produces an unambiguous name because even though MPKGPATH
  // can be anything, we know that MNAME does not contain a dot.  The
  // dot we return here, between MPKGPATH and MNAME, will wind up
  // being underscore encoded.
  std::string ret(mpkgpath);
  ret.push_back('.');
  ret.append(Gogo::unpack_hidden_name(mname));
  ret.append("..stub");
  return ret;
}

// Set BNAME to the name of the hash function for TYPE.

void
Gogo::hash_function_name(const Type* type, Backend_name* bname)
{
  if (type->named_type() != NULL)
    type->backend_name(this, bname);
  else
    {
      bname->add(this->pkgpath());
      type->backend_name(this, bname);
    }
  bname->set_suffix("..hash");
}

// Set BNAME to the name of the equal function for TYPE.  If NAME is
// not NULL it is the name of the type.

void
Gogo::equal_function_name(const Type* type, const Named_type* name,
			  Backend_name* bname)
{
  if (name != NULL)
    name->backend_name(this, bname);
  else
    {
      bname->add(this->pkgpath());
      type->backend_name(this, bname);
    }
  bname->set_suffix("..eq");
}

// Set BNAME to the 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.

void
Gogo::global_var_backend_name(const std::string& go_name,
			      const Package* package,
			      Backend_name* bname)
{
  if (package == NULL)
    bname->add(this->pkgpath());
  else
    bname->add(package->pkgpath());
  bname->add(Gogo::unpack_hidden_name(go_name));
}

// Return an erroneous name that indicates that an error has already
// been reported.  This name will act like a Go identifier.

std::string
Gogo::erroneous_name()
{
  go_assert(saw_errors());
  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.  This name will act like a Go
// identifier.  The name returned here will eventually be passed to
// function_backend_name, which will pull off the ..thunk as an
// unencoded suffix.

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;
  // We don't want to return a name that starts with a dot, as that
  // will confuse Gogo::is_hidden_name.  And we don't want to change
  // ..thunk, which fits our general theme and is used by code like
  // runtime.Callers.  But the prefix doesn't matter, as the actual
  // name will include the package path.
  std::string ret = "go";
  return ret + thunk_name;
}

// Return whether a function is a thunk.

bool
Gogo::is_thunk(const Named_object* no)
{
  const std::string& name(no->name());
  size_t i = name.rfind("..thunk");
  if (i == std::string::npos)
    return false;
  return Gogo::is_digits(name.substr(i + 7));
}

// 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 this->pkgpath() + buf;
}

// Return the name to use for a nested function.  This name acts like
// a Go identifier.  This name will be rewritten by
// Function::backend_name.

std::string
Gogo::nested_function_name(Named_object* enclosing)
{
  std::string prefix;
  unsigned int index;
  if (enclosing == NULL)
    {
      // A function literal at top level, as in
      // var f = func() {}
      static unsigned int toplevel_index;
      ++toplevel_index;
      index = toplevel_index;
      prefix = ".go";
    }
  else
    {
      while (true)
	{
	  Named_object* parent = enclosing->func_value()->enclosing();
	  if (parent == NULL)
	    break;
	  enclosing = parent;
	}
      const Typed_identifier* rcvr =
	enclosing->func_value()->type()->receiver();
      if (rcvr != NULL)
	{
	  Backend_name bname;
	  rcvr->type()->backend_name(this, &bname);
	  prefix = bname.name();
	  prefix.push_back('.');
	}
      prefix.append(Gogo::unpack_hidden_name(enclosing->name()));
      index = enclosing->func_value()->next_nested_function_index();
    }
  char buf[30];
  snprintf(buf, sizeof buf, "..func%u", index);
  return prefix + buf;
}

// 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.  This is a
// name that acts like a Go identifier.

std::string
Gogo::recover_thunk_name(const std::string& name, const Type* rtype)
{
  std::string ret;
  if (rtype != NULL)
    {
      Backend_name bname;
      rtype->deref()->backend_name(this, &bname);
      ret = bname.name();
      ret.append(1, '.');
    }
  if (Gogo::special_name_pos(name) != std::string::npos)
    ret.append(name);
  else
    ret.append(Gogo::unpack_hidden_name(name));
  ret.append("..r");
  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 "go..C0";
}

// 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];
  ++counter;
  snprintf(buf, sizeof buf, "go..C%u", counter);
  return buf;
}

// Return the assembler 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.  This name
// is handled specially by Function::backend_name.  It is not encoded
// further.

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 the name for a dummy init function, which is not a real
// function but only for tracking transitive import.

std::string
Gogo::dummy_init_fn_name()
{
  return "~" + this->pkgpath_symbol();
}

// Return the package path symbol from an init function name, which
// can be a real init function or a dummy one.

std::string
Gogo::pkgpath_symbol_from_init_fn_name(std::string name)
{
  go_assert(!name.empty());
  if (name[0] == '~')
    return name.substr(1);
  size_t pos = name.find("..import");
  if (pos != std::string::npos)
    return name.substr(0, pos);
  go_unreachable();
}

// Set BNAME to a name for a type to use in a symbol.  Return a name
// for a type to use in a symbol.  These names appear in symbol names
// in the assembler file for things like type descriptors and methods.

void
Type::backend_name(Gogo* gogo, Backend_name* bname) const
{
  // Special case top level named types to get nicer name encodings
  // for this common case.
  const Named_type* nt = this->unalias()->named_type();
  if (nt != NULL && !nt->is_builtin())
    {
      unsigned int index;
      if (nt->in_function(&index) == NULL)
	{
	  const Named_object* no = nt->named_object();
	  if (no->package() == NULL)
	    bname->add(gogo->pkgpath());
	  else
	    bname->add(no->package()->pkgpath());
	  bname->add(Gogo::unpack_hidden_name(no->name()));
	  return;
	}
    }

  std::string name;
  bool is_non_identifier = false;

  // The do_symbol_name virtual function will set RET to the mangled
  // name before encoding.
  this->do_mangled_name(gogo, &name, &is_non_identifier);

  bname->add(name);
  if (is_non_identifier)
    bname->set_is_non_identifier();
}

// The mangled name is implemented as a method on each instance of
// Type.

void
Error_type::do_mangled_name(Gogo*, std::string* ret,
			    bool* is_non_identifier) const
{
  ret->append("{error}");
  *is_non_identifier = true;
}

void
Void_type::do_mangled_name(Gogo*, std::string* ret,
			   bool* is_non_identifier) const
{
  ret->append("{void}");
  *is_non_identifier = true;
}

void
Boolean_type::do_mangled_name(Gogo*, std::string* ret, bool*) const
{
  ret->append("bool");
}

void
Integer_type::do_mangled_name(Gogo*, std::string* ret,
			      bool* is_non_identifier) const
{
  char buf[100];
  snprintf(buf, sizeof buf, "%s%si%d",
	   this->is_abstract_ ? "{abstract}" : "",
	   this->is_unsigned_ ? "u" : "",
	   this->bits_);
  ret->append(buf);
  if (this->is_abstract_)
    *is_non_identifier = true;
}

void
Float_type::do_mangled_name(Gogo*, std::string* ret,
			    bool* is_non_identifier) const
{
  char buf[100];
  snprintf(buf, sizeof buf, "%sfloat%d",
	   this->is_abstract_ ? "{abstract}" : "",
	   this->bits_);
  ret->append(buf);
  if (this->is_abstract_)
    *is_non_identifier = true;
}

void
Complex_type::do_mangled_name(Gogo*, std::string* ret,
			      bool* is_non_identifier) const
{
  char buf[100];
  snprintf(buf, sizeof buf, "%sc%d",
	   this->is_abstract_ ? "{abstract}" : "",
	   this->bits_);
  ret->append(buf);
  if (this->is_abstract_)
    *is_non_identifier = true;
}

void
String_type::do_mangled_name(Gogo*, std::string* ret, bool*) const
{
  ret->append("string");
}

void
Function_type::do_mangled_name(Gogo* gogo, std::string* ret,
			       bool* is_non_identifier) const
{
  ret->append("func");

  if (this->receiver_ != NULL)
    {
      ret->push_back('(');
      this->append_mangled_name(this->receiver_->type(), gogo, ret,
				is_non_identifier);
      ret->append(")");
    }

  ret->push_back('(');
  const Typed_identifier_list* params = this->parameters();
  if (params != NULL)
    {
      bool first = true;
      for (Typed_identifier_list::const_iterator p = params->begin();
	   p != params->end();
	   ++p)
	{
	  if (first)
	    first = false;
	  else
	    ret->push_back(',');
	  if (this->is_varargs_ && p + 1 == params->end())
	    ret->append("...");
	  this->append_mangled_name(p->type(), gogo, ret,
				    is_non_identifier);
	}
    }
  ret->push_back(')');

  ret->push_back('(');
  const Typed_identifier_list* results = this->results();
  if (results != NULL)
    {
      bool first = true;
      for (Typed_identifier_list::const_iterator p = results->begin();
	   p != results->end();
	   ++p)
	{
	  if (first)
	    first = false;
	  else
	    ret->append(",");
	  this->append_mangled_name(p->type(), gogo, ret, is_non_identifier);
	}
    }
  ret->push_back(')');

  *is_non_identifier = true;
}

void
Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret,
			      bool* is_non_identifier) const
{
  ret->push_back('*');
  this->append_mangled_name(this->to_type_, gogo, ret, is_non_identifier);
  *is_non_identifier = true;
}

void
Nil_type::do_mangled_name(Gogo*, std::string* ret,
			  bool* is_non_identifier) const
{
  ret->append("{nil}");
  *is_non_identifier = true;
}

void
Struct_type::do_mangled_name(Gogo* gogo, std::string* ret,
			     bool* is_non_identifier) const
{
  ret->append("struct{");

  if (this->is_struct_incomparable_)
    ret->append("{x}");

  const Struct_field_list* fields = this->fields_;
  if (fields != NULL)
    {
      bool first = true;
      for (Struct_field_list::const_iterator p = fields->begin();
	   p != fields->end();
	   ++p)
	{
	  if (first)
	    first = false;
	  else
	    ret->push_back(';');

	  if (!p->is_anonymous())
	    {
              Gogo::append_possibly_hidden_name(ret, p->field_name());
	      ret->push_back(' ');
	    }

	  const Type* ft = p->type();
	  const Named_type* nt = ft->named_type();

	  if (p->is_anonymous() && nt != NULL && nt->is_builtin())
	    {
	      // For an embedded field with a builtin type, we must
	      // include a package path.  Otherwise embedding builtin
	      // types in different packages will produce identical
	      // types, which shouldn't happen because the builtin
	      // types are not exported.
	      ret->append(gogo->pkgpath());
	      ret->push_back('.');
	      nt->append_symbol_type_name(gogo, true, ret, is_non_identifier);
	    }
	  else if (p->is_anonymous() && nt != NULL && nt->is_alias())
	    {
	      // For an anonymous field with an alias type, the field name
	      // is the alias name.
	      nt->append_symbol_type_name(gogo, true, ret, is_non_identifier);
	    }
	  else
	    this->append_mangled_name(ft, gogo, ret, is_non_identifier);

	  if (p->has_tag())
	    {
	      // Use curly braces around a struct tag, since they are
	      // unambiguous here and struct tags rarely contain curly
	      // braces.
	      ret->push_back('{');
	      ret->append(go_mangle_struct_tag(p->tag()));
	      ret->push_back('}');
	    }
	}
    }

  ret->push_back('}');

  *is_non_identifier = true;
}

void
Array_type::do_mangled_name(Gogo* gogo, std::string* ret,
			    bool* is_non_identifier) const
{
  ret->push_back('[');
  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->append("x");
    }
  ret->push_back(']');
  this->append_mangled_name(this->element_type_, gogo, ret, is_non_identifier);
  *is_non_identifier = true;
}

void
Map_type::do_mangled_name(Gogo* gogo, std::string* ret,
			  bool* is_non_identifier) const
{
  ret->append("map[");
  this->append_mangled_name(this->key_type_, gogo, ret, is_non_identifier);
  ret->push_back(']');
  this->append_mangled_name(this->val_type_, gogo, ret, is_non_identifier);
  *is_non_identifier = true;
}

void
Channel_type::do_mangled_name(Gogo* gogo, std::string* ret,
			      bool* is_non_identifier) const
{
  if (!this->may_send_)
    ret->append("<-");
  ret->append("chan");
  if (!this->may_receive_)
    ret->append("<-");
  ret->push_back(' ');
  this->append_mangled_name(this->element_type_, gogo, ret, is_non_identifier);
  *is_non_identifier = true;
}

void
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret,
				bool* is_non_identifier) const
{
  go_assert(this->methods_are_finalized_);

  ret->append("interface{");

  const Typed_identifier_list* methods = this->all_methods_;
  if (methods != NULL && !this->seen_)
    {
      this->seen_ = true;
      bool first = true;
      for (Typed_identifier_list::const_iterator p = methods->begin();
	   p != methods->end();
	   ++p)
	{
	  if (first)
	    first = false;
	  else
	    ret->push_back(';');

	  if (!p->name().empty())
	    {
              Gogo::append_possibly_hidden_name(ret, p->name());
	      ret->push_back(' ');
	    }

	  this->append_mangled_name(p->type(), gogo, ret, is_non_identifier);
	}
      this->seen_ = false;
    }

  ret->push_back('}');

  *is_non_identifier = true;
}

void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret,
			    bool* is_non_identifier) const
{
  this->append_symbol_type_name(gogo, false, ret, is_non_identifier);
}

void
Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret,
					  bool *is_non_identifier) const
{
  if (this->is_defined())
    this->append_mangled_name(this->real_type(), gogo, ret, is_non_identifier);
  else
    {
      const Named_object* no = this->named_object();
      if (no->package() == NULL)
	ret->append(gogo->pkgpath());
      else
	ret->append(no->package()->pkgpath());
      ret->push_back('.');
      ret->append(Gogo::unpack_hidden_name(no->name()));
    }
}

// Append the symbol 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_symbol_type_name(Gogo* gogo, bool use_alias,
				    std::string* ret,
				    bool* is_non_identifier) 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, is_non_identifier);
      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
    {
      if (this->in_function_ != NULL)
	{
	  const Typed_identifier* rcvr =
	    this->in_function_->func_value()->type()->receiver();
	  if (rcvr != NULL)
	    {
	      Backend_name bname;
	      rcvr->type()->deref()->backend_name(gogo, &bname);
	      ret->append(bname.name());
	      if (bname.is_non_identifier())
		*is_non_identifier = true;
	    }
	  else if (this->in_function_->package() == NULL)
	    ret->append(gogo->pkgpath());
	  else
	    ret->append(this->in_function_->package()->pkgpath());
	  ret->push_back('.');
	  ret->append(Gogo::unpack_hidden_name(this->in_function_->name()));
	}
      else
	{
	  if (no->package() == NULL)
	    ret->append(gogo->pkgpath());
	  else
	    ret->append(no->package()->pkgpath());
	}
      ret->push_back('.');
    }

  ret->append(Gogo::unpack_hidden_name(no->name()));

  if (this->in_function_ != NULL && this->in_function_index_ > 0)
    {
      char buf[30];
      snprintf(buf, sizeof buf, ".i%u", this->in_function_index_);
      ret->append(buf);
    }
}

// Given a name which may or may not have been hidden, append the
// appropriate version of the name to the result string.

void
Gogo::append_possibly_hidden_name(std::string *result, const std::string& name)
{
  if (!Gogo::is_hidden_name(name))
    *result += name;
  else
    *result += name.substr(1);
}

// Set BNAME to 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.

void
Gogo::type_descriptor_backend_name(const Type* type, Named_type* nt,
				   Backend_name* bname)
{
  // 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 for all unsafe pointer types.
  if (type->is_unsafe_pointer_type())
    {
      bname->set_asm_name("unsafe.Pointer..d");
      return;
    }

  bool is_pointer = false;
  if (nt == NULL && type->points_to() != NULL)
    {
      nt = type->points_to()->unalias()->named_type();
      is_pointer = true;
    }

  if (nt == NULL)
    {
      // Sanity check: we should never generate a type descriptor for
      // an unnamed primitive type.  For those we should always be
      // using a named type, like "int".
      go_assert(!type->is_basic_type());

      type->backend_name(this, bname);
      bname->set_prefix("type..");
    }
  else
    {
      nt->backend_name(this, bname);
      bname->set_suffix(is_pointer ? "..p" : "..d");
    }
}

// Return the name of the type descriptor list symbol of a package.
// This is passed directly to the backend without further encoding.

std::string
Gogo::type_descriptor_list_symbol(const std::string& pkgpath_symbol)
{
  return pkgpath_symbol + "..types";
}

// Return the name of the list of all type descriptor lists.  This is
// only used in the main package.  This is passed directly to the
// backend without further encoding.

std::string
Gogo::typelists_symbol()
{
  return "go..typelists";
}

// Return the assembler 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.)
// This is passed directly to the backend without further encoding.

std::string
Gogo::gc_symbol_name(Type* type)
{
  Backend_name bname;
  this->type_descriptor_backend_name(type, type->named_type(), &bname);
  bname.append_suffix("..g");
  return bname.asm_name();
}

// Return the assembler name for a ptrmask variable.  PTRMASK_SYM_NAME
// is a base32 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.)  This is passed directly to the backend without
// further encoding.

std::string
Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name)
{
  return "gcbits.." + ptrmask_sym_name;
}

// Return the assembler 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.  This is passed directly to the backend without further
// encoding.

std::string
Gogo::interface_method_table_name(Interface_type* itype, Type* type,
				  bool is_pointer)
{
  Backend_name iname;
  itype->backend_name(this, &iname);
  Backend_name tname;
  type->backend_name(this, &tname);
  return ((is_pointer ? "pimt.." : "imt..")
	  + iname.asm_name()
	  + ".."
	  + tname.asm_name());
}

// If NAME is a special name with a ".." suffix, return the position
// of that suffix.  This is needed because various special names use
// "..SUFFIX", but unpack_hidden_name just looks for '.', and because
// we don't want to encode the suffix.

size_t
Gogo::special_name_pos(const std::string& name)
{
  size_t pos = name.rfind("..");
  if (pos == std::string::npos)
    return pos;
  std::string suffix(name.substr(pos));
  if (suffix == "..hash"
      || suffix == "..eq"
      || suffix == "..stub"
      || suffix == "..d"
      || suffix == "..f"
      || suffix == "..r"
      || suffix == "..import")
    return pos;
  if ((suffix.compare(2, 4, "func") == 0
       || suffix.compare(2, 4, "init") == 0)
      && Gogo::is_digits(suffix.substr(6)))
    return pos;
  if (suffix.compare(2, 5, "thunk") == 0
      && Gogo::is_digits(suffix.substr(7)))
    return pos;
  return std::string::npos;
}

// Return whether the string is non-empty and contains only digits.

bool
Gogo::is_digits(const std::string& s)
{
  if (s.empty())
    return false;
  for (size_t i = 0; i < s.size(); ++i)
    if (s[i] < '0' || s[i] > '9')
      return false;
  return true;
}

// Class Backend_name.

// Get the user visible name.

std::string
Backend_name::name() const
{
  if (this->is_asm_name_)
    return this->components_[0];

  // If there is some character in the name that can't appear in an
  // identifier, use the assembler name as the user name.  This avoids
  // possible problems in the assembler or debugger.  The usual
  // demangling scheme will still work.  We use a prefix of "g." to
  // tell the debugger about this.
  if (this->is_non_identifier_)
    return "g." + this->asm_name();

  std::string ret;
  if (this->prefix_ != NULL)
    ret.append(this->prefix_);
  for (int i = 0; i < this->count_; i++)
    {
      if (i > 0)
	ret.push_back('.');
      ret.append(this->components_[i]);
    }
  if (!this->suffix_.empty())
    ret.append(this->suffix_);
  return ret;
}

// Get the assembler name.

std::string
Backend_name::asm_name() const
{
  if (this->is_asm_name_)
    return this->components_[0];
  std::string ret;
  if (this->prefix_ != NULL)
    ret.append(this->prefix_);
  for (int i = 0; i < this->count_; i++)
    {
      if (i > 0)
	ret.push_back('.');
      ret.append(go_encode_id(this->components_[i]));
    }
  if (!this->suffix_.empty())
    ret.append(this->suffix_);
  return ret;
}

// Get the assembler name, or the empty string if it is the same as
// the user visible name.

std::string
Backend_name::optional_asm_name() const
{
  if (this->is_asm_name_)
    return "";
  if (this->is_non_identifier_)
    return this->asm_name();
  for (int i = 0; i < this->count_; i++)
    if (go_id_needs_encoding(this->components_[i]))
      return this->asm_name();
  return "";
}