| // 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 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 names can not contain dot, so we rely | 
 | // on using dot to encode Unicode characters, and to separate Go | 
 | // symbols by package, and so forth.  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.  These never start with a dot, never end | 
 | // with a dot, never contain two consecutive dots, and never contain a | 
 | // dot followed by a digit. | 
 | // | 
 | // 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.  PKGPATH is the | 
 | // -fgo-pkgpath option as adjusted by Gogo::pkgpath_for_symbol.  Note | 
 | // that PKGPATH can not contain a dot and neither can NAME.  Also, | 
 | // NAME may not begin with a digit.  NAME may require further encoding | 
 | // for non-ASCII characters as described below, but until that | 
 | // encoding these symbols contain exactly one dot, and they do not | 
 | // start with a dot. | 
 | // | 
 | // The external name for a method NAME for a named type TYPE is | 
 | // "PKGPATH.TYPE.NAME".  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.  Here none of | 
 | // PKGPATH, TYPE, or NAME can be empty or contain a dot, and neither | 
 | // TYPE nor NAME may begin with a digit.  Before encoding these 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.TYPE.NAME, where TYPE is an | 
 | // approximately readable version of the type literal, described | 
 | // below.  As the type literal encoding always contains multiple dots, | 
 | // these names always contain more than two dots.  Although the type | 
 | // literal encoding contains dots, neither PKGPATH nor NAME can | 
 | // contain a dot, and neither TYPE nor NAME can begin with a digit. | 
 | // The effect is that PKGPATH is always the portion of the name before | 
 | // the first dot and NAME is always the portion after the last dot. | 
 | // 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" where NN is a sequence of digits (these | 
 | // functions are never globally visible).  Thus the final name of a | 
 | // thunk will be PKGPATH..thunkNN. | 
 | // | 
 | // An init function is treated as a function whose name is ".initNN" | 
 | // 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. | 
 | // | 
 | // A nested function is given the name of outermost enclosing function | 
 | // or method with an added suffix "..funcNN" 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.TYPE..d. | 
 | // | 
 | // The name of a type descriptor for an unnamed type is type..TYPE. | 
 | // That is, the string "type.." followed by the type literal encoding. | 
 | // 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 type literal | 
 | // encoding can never start with a digit or with 'u' or 'U'. | 
 | // | 
 | // The name of the GC symbol for a named type is PKGPATH.TYPE..g. | 
 | // | 
 | // The name of the GC symbol for an unnamed type is typeg..TYPE. | 
 | // 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 without 'u' | 
 | // or 'U'.  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.  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. | 
 | // | 
 | // 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 | 
 | // are quoted inside curly braces, rather than introduce an encoding | 
 | // for quotes.  Struct tags can contain any character, so any single | 
 | // byte Unicode character that is not alphanumeric or underscore is | 
 | // replaced with .xNN where NN is the hex encoding. | 
 | // | 
 | // There is a simple encoding for glue characters in type literals: | 
 | //   .0 - ' ' | 
 | //   .1 - '*' | 
 | //   .2 - ';' | 
 | //   .3 - ',' | 
 | //   .4 - '{' | 
 | //   .5 - '}' | 
 | //   .6 - '[' | 
 | //   .7 - ']' | 
 | //   .8 - '(' | 
 | //   .9 - ')' | 
 | // This is unambiguous as, although the type literal can contain a dot | 
 | // as shown above, those dots are always followed by a name and names | 
 | // can not begin with a digit.  A dot is always followed by a name or | 
 | // a digit, and a type literal can neither start nor end with a dot, | 
 | // so this never introduces consecutive dots. | 
 | // | 
 | // Struct tags can contain any character, so they need special | 
 | // treatment.  Alphanumerics, underscores, and Unicode characters that | 
 | // require more than a single byte are left alone (Unicode characters | 
 | // will be encoded later, as described below).  Other single bytes | 
 | // characters are replace with .xNN where NN is the hex encoding. | 
 | // | 
 | // Since Go identifiers can contain Unicode characters, we must encode | 
 | // them into ASCII.  We do this last, after the name is generated as | 
 | // described above and after type literals are encoded.  To make the | 
 | // encoding unambiguous, we introduce it with two consecutive dots. | 
 | // This is followed by the letter u and four hex digits or the letter | 
 | // U and eight digits, just as in the language only using ..u and ..U | 
 | // instead of \u and \U.  Since before this encoding names can never | 
 | // contain consecutive dots followed by 'u' or 'U', and after this | 
 | // encoding "..u" and "..U" are followed by a known number of | 
 | // characters, this is unambiguous. | 
 | // | 
 | // Demangling these names is straightforward: | 
 | //  - replace ..uXXXX with a unicode character | 
 | //  - replace ..UXXXXXXXX with a unicode character | 
 | //  - replace .D, where D is a digit, with the character from the above | 
 | // That will get you as close as possible to a readable name. | 
 |  | 
 | // 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; | 
 |   if (rtype != NULL) | 
 |     ret = rtype->deref()->mangled_name(this); | 
 |   else if (package == NULL) | 
 |     ret = this->pkgpath_symbol(); | 
 |   else | 
 |     ret = package->pkgpath_symbol(); | 
 |   ret.push_back('.'); | 
 |   // Check for special names that will break if we use | 
 |   // Gogo::unpack_hidden_name. | 
 |   if (Gogo::is_special_name(go_name)) | 
 |     ret.append(go_name); | 
 |   else | 
 |     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) | 
 | { | 
 |   if (no->is_function() && !no->func_value()->asm_name().empty()) | 
 |     return no->func_value()->asm_name() + "..f"; | 
 |   else if (no->is_function_declaration() | 
 | 	   && !no->func_declaration_value()->asm_name().empty()) | 
 |     return no->func_declaration_value()->asm_name() + "..f"; | 
 |   std::string ret = this->function_asm_name(no->name(), no->package(), NULL); | 
 |   ret.append("..f"); | 
 |   return ret; | 
 | } | 
 |  | 
 | // Return the name to use for a generated stub method.  MNAME is the | 
 | // method name.  PACKAGE is the package where the type that needs this | 
 | // stub method is defined.  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 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.  We need to disambiguate the method name. | 
 |   std::string ret = this->pkgpath_symbol_for_package(mpkgpath); | 
 |   ret.push_back('.'); | 
 |   ret.append(Gogo::unpack_hidden_name(mname)); | 
 |   ret.append("..stub"); | 
 |   return ret; | 
 | } | 
 |  | 
 | // 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) | 
 | { | 
 |   const Type* rtype = type; | 
 |   if (name != NULL) | 
 |     rtype = name; | 
 |   std::string tname = rtype->mangled_name(this); | 
 |   *hash_name = tname + "..hash"; | 
 |   *equal_name = tname + "..eq"; | 
 | } | 
 |  | 
 | // 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) | 
 | { | 
 |   std::string ret; | 
 |   if (package == NULL) | 
 |     ret = this->pkgpath_symbol(); | 
 |   else | 
 |     ret = package->pkgpath_symbol(); | 
 |   ret.append(1, '.'); | 
 |   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() | 
 | { | 
 |   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. | 
 |  | 
 | 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; | 
 |   std::string ret = this->pkgpath_symbol(); | 
 |   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.find("..thunk"); | 
 |   if (i == std::string::npos) | 
 |     return false; | 
 |   for (i += 7; i < name.size(); ++i) | 
 |     if (name[i] < '0' || name[i] > '9') | 
 |       return false; | 
 |   return true; | 
 | } | 
 |  | 
 | // 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; | 
 |   std::string ret = this->pkgpath_symbol(); | 
 |   return ret + buf; | 
 | } | 
 |  | 
 | // Return the name to use for a nested function. | 
 |  | 
 | 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) | 
 | 	{ | 
 | 	  prefix = rcvr->type()->mangled_name(this); | 
 | 	  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. | 
 |  | 
 | std::string | 
 | Gogo::recover_thunk_name(const std::string& name, const Type* rtype) | 
 | { | 
 |   std::string ret; | 
 |   if (rtype != NULL) | 
 |     { | 
 |       ret = rtype->mangled_name(this); | 
 |       ret.append(1, '.'); | 
 |     } | 
 |   if (Gogo::is_special_name(name)) | 
 |     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 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 will set RET to the mangled | 
 |   // name before glue character mapping. | 
 |   this->do_mangled_name(gogo, &ret); | 
 |  | 
 |   // Type descriptor names and interface method table names use a ".." | 
 |   // before the mangled name of a type, so to avoid ambiguity the | 
 |   // mangled name must not start with 'u' or 'U' or a digit. | 
 |   go_assert((ret[0] < '0' || ret[0] > '9') && ret[0] != ' '); | 
 |   if (ret[0] == 'u' || ret[0] == 'U') | 
 |     ret = " " + ret; | 
 |  | 
 |   // Map glue characters as described above. | 
 |  | 
 |   // The mapping is only unambiguous if there is no .DIGIT in the | 
 |   // string, so check that. | 
 |   for (size_t i = ret.find('.'); | 
 |        i != std::string::npos; | 
 |        i = ret.find('.', i + 1)) | 
 |     { | 
 |       if (i + 1 < ret.size()) | 
 | 	{ | 
 | 	  char c = ret[i + 1]; | 
 | 	  go_assert(c < '0' || c > '9'); | 
 | 	} | 
 |     } | 
 |  | 
 |   // The order of these characters is the replacement code. | 
 |   const char * const replace = " *;,{}[]()"; | 
 |  | 
 |   const size_t rlen = strlen(replace); | 
 |   char buf[2]; | 
 |   buf[0] = '.'; | 
 |   for (size_t ri = 0; ri < rlen; ++ri) | 
 |     { | 
 |       buf[1] = '0' + ri; | 
 |       while (true) | 
 | 	{ | 
 | 	  size_t i = ret.find(replace[ri]); | 
 | 	  if (i == std::string::npos) | 
 | 	    break; | 
 | 	  ret.replace(i, 1, buf, 2); | 
 | 	} | 
 |     } | 
 |  | 
 |   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->append("{error}"); | 
 | } | 
 |  | 
 | void | 
 | Void_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   ret->append("{void}"); | 
 | } | 
 |  | 
 | void | 
 | Boolean_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   ret->append("bool"); | 
 | } | 
 |  | 
 | void | 
 | Integer_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   char buf[100]; | 
 |   snprintf(buf, sizeof buf, "%s%si%d", | 
 | 	   this->is_abstract_ ? "{abstract}" : "", | 
 | 	   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, "%sfloat%d", | 
 | 	   this->is_abstract_ ? "{abstract}" : "", | 
 | 	   this->bits_); | 
 |   ret->append(buf); | 
 | } | 
 |  | 
 | void | 
 | Complex_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   char buf[100]; | 
 |   snprintf(buf, sizeof buf, "%sc%d", | 
 | 	   this->is_abstract_ ? "{abstract}" : "", | 
 | 	   this->bits_); | 
 |   ret->append(buf); | 
 | } | 
 |  | 
 | void | 
 | String_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   ret->append("string"); | 
 | } | 
 |  | 
 | void | 
 | Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const | 
 | { | 
 |   ret->append("func"); | 
 |  | 
 |   if (this->receiver_ != NULL) | 
 |     { | 
 |       ret->push_back('('); | 
 |       this->append_mangled_name(this->receiver_->type(), gogo, ret); | 
 |       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()) | 
 | 	    { | 
 | 	      // We can't use "..." here because the mangled name | 
 | 	      // might start with 'u' or 'U', which would be ambiguous | 
 | 	      // with the encoding of Unicode characters. | 
 | 	      ret->append(",,,"); | 
 | 	    } | 
 | 	  this->append_mangled_name(p->type(), gogo, ret); | 
 | 	} | 
 |     } | 
 |   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); | 
 | 	} | 
 |     } | 
 |   ret->push_back(')'); | 
 | } | 
 |  | 
 | void | 
 | Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const | 
 | { | 
 |   ret->push_back('*'); | 
 |   this->append_mangled_name(this->to_type_, gogo, ret); | 
 | } | 
 |  | 
 | void | 
 | Nil_type::do_mangled_name(Gogo*, std::string* ret) const | 
 | { | 
 |   ret->append("{nil}"); | 
 | } | 
 |  | 
 | void | 
 | Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) 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()) | 
 | 	    { | 
 | 	      ret->append(Gogo::mangle_possibly_hidden_name(p->field_name())); | 
 | 	      ret->push_back(' '); | 
 | 	    } | 
 |  | 
 | 	  // 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()) | 
 | 	    { | 
 | 	      // Use curly braces around a struct tag, since they are | 
 | 	      // unambiguous here and we have no encoding for | 
 | 	      // quotation marks. | 
 | 	      ret->push_back('{'); | 
 | 	      ret->append(go_mangle_struct_tag(p->tag())); | 
 | 	      ret->push_back('}'); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   ret->push_back('}'); | 
 | } | 
 |  | 
 | void | 
 | Array_type::do_mangled_name(Gogo* gogo, std::string* ret) 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); | 
 | } | 
 |  | 
 | void | 
 | Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const | 
 | { | 
 |   ret->append("map["); | 
 |   this->append_mangled_name(this->key_type_, gogo, ret); | 
 |   ret->push_back(']'); | 
 |   this->append_mangled_name(this->val_type_, gogo, ret); | 
 | } | 
 |  | 
 | void | 
 | Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) 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); | 
 | } | 
 |  | 
 | void | 
 | Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) 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()) | 
 | 	    { | 
 | 	      ret->append(Gogo::mangle_possibly_hidden_name(p->name())); | 
 | 	      ret->push_back(' '); | 
 | 	    } | 
 |  | 
 | 	  this->append_mangled_name(p->type(), gogo, ret); | 
 | 	} | 
 |       this->seen_ = false; | 
 |     } | 
 |  | 
 |   ret->push_back('}'); | 
 | } | 
 |  | 
 | 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(); | 
 |       if (no->package() == NULL) | 
 | 	ret->append(gogo->pkgpath_symbol()); | 
 |       else | 
 | 	ret->append(no->package()->pkgpath_symbol()); | 
 |       ret->push_back('.'); | 
 |       ret->append(Gogo::unpack_hidden_name(no->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 | 
 |     { | 
 |       if (this->in_function_ != NULL) | 
 | 	{ | 
 | 	  const Typed_identifier* rcvr = | 
 | 	    this->in_function_->func_value()->type()->receiver(); | 
 | 	  if (rcvr != NULL) | 
 | 	    ret->append(rcvr->type()->deref()->mangled_name(gogo)); | 
 | 	  else if (this->in_function_->package() == NULL) | 
 | 	    ret->append(gogo->pkgpath_symbol()); | 
 | 	  else | 
 | 	    ret->append(this->in_function_->package()->pkgpath_symbol()); | 
 | 	  ret->push_back('.'); | 
 | 	  ret->append(Gogo::unpack_hidden_name(this->in_function_->name())); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (no->package() == NULL) | 
 | 	    ret->append(gogo->pkgpath_symbol()); | 
 | 	  else | 
 | 	    ret->append(no->package()->pkgpath_symbol()); | 
 | 	} | 
 |       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); | 
 |     } | 
 | } | 
 |  | 
 | // 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 for all unsafe pointer types. | 
 |   if (type->is_unsafe_pointer_type()) | 
 |     return "unsafe.Pointer..d"; | 
 |  | 
 |   if (nt == NULL) | 
 |     return "type.." + type->mangled_name(this); | 
 |  | 
 |   std::string ret; | 
 |   Named_object* no = nt->named_object(); | 
 |   unsigned int index; | 
 |   const Named_object* in_function = nt->in_function(&index); | 
 |   if (nt->is_builtin()) | 
 |     go_assert(in_function == NULL); | 
 |   else | 
 |     { | 
 |       if (in_function != NULL) | 
 | 	{ | 
 | 	  const Typed_identifier* rcvr = | 
 | 	    in_function->func_value()->type()->receiver(); | 
 | 	  if (rcvr != NULL) | 
 | 	    ret.append(rcvr->type()->deref()->mangled_name(this)); | 
 | 	  else if (in_function->package() == NULL) | 
 | 	    ret.append(this->pkgpath_symbol()); | 
 | 	  else | 
 | 	    ret.append(in_function->package()->pkgpath_symbol()); | 
 | 	  ret.push_back('.'); | 
 | 	  ret.append(Gogo::unpack_hidden_name(in_function->name())); | 
 | 	  ret.push_back('.'); | 
 | 	} | 
 |  | 
 |       if (no->package() == NULL) | 
 | 	ret.append(this->pkgpath_symbol()); | 
 |       else | 
 | 	ret.append(no->package()->pkgpath_symbol()); | 
 |       ret.push_back('.'); | 
 |     } | 
 |  | 
 |   ret.append(Gogo::mangle_possibly_hidden_name(no->name())); | 
 |  | 
 |   if (in_function != NULL && index > 0) | 
 |     { | 
 |       char buf[30]; | 
 |       snprintf(buf, sizeof buf, "..i%u", index); | 
 |       ret.append(buf); | 
 |     } | 
 |  | 
 |   ret.append("..d"); | 
 |  | 
 |   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()) + "..g"; | 
 | } | 
 |  | 
 | // Return the 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.) | 
 |  | 
 | std::string | 
 | Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name) | 
 | { | 
 |   return "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 ? "pimt.." : "imt..") | 
 | 	  + itype->mangled_name(this) | 
 | 	  + ".." | 
 | 	  + type->mangled_name(this)); | 
 | } | 
 |  | 
 | // Return whether NAME is a special name that can not be passed to | 
 | // unpack_hidden_name.  This is needed because various special names | 
 | // use "..SUFFIX", but unpack_hidden_name just looks for '.'. | 
 |  | 
 | bool | 
 | Gogo::is_special_name(const std::string& name) | 
 | { | 
 |   return (name.find("..hash") != std::string::npos | 
 | 	  || name.find("..eq") != std::string::npos | 
 | 	  || name.find("..stub") != std::string::npos | 
 | 	  || name.find("..func") != std::string::npos | 
 | 	  || name.find("..r") != std::string::npos | 
 | 	  || name.find("..init") != std::string::npos | 
 | 	  || name.find("..thunk") != std::string::npos | 
 | 	  || name.find("..import") != std::string::npos); | 
 | } |