compiler: relocate ID encoding utilities to gofrontend
authorThan McIntosh <thanm@google.com>
Tue, 22 Nov 2016 22:28:05 +0000 (22:28 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 22 Nov 2016 22:28:05 +0000 (22:28 +0000)
    Relocate the code that encodes/sanitizes identifiers to make them
    assembler-friendly, moving it from the back end to the front end; the
    decisions about when to encode an identifier and the calls to the
    encoding helpers now take place entirely in gofrontend.

    Reviewed-on: https://go-review.googlesource.com/33424

* go-gcc.cc (char_needs_encoding): Remove.
(needs_encoding, fetch_utf8_char, encode_id): Remove.
(Gcc_backend::global_variable): Add asm_name parameter.  Don't
compute asm_name here.
(Gcc_backend::implicit_variable): Likewise.
(Gcc_backend::implicit_variable_reference): Likewise.
(Gcc_backend::immutable_struct): Likewise.
(Gcc_backend::immutable_struct_reference): Likewise.
* Make-lang.in (GO_OBJS): Add go/go-encode-id.o.

From-SVN: r242726

gcc/go/ChangeLog
gcc/go/Make-lang.in
gcc/go/go-gcc.cc
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/go-encode-id.cc [new file with mode: 0644]
gcc/go/gofrontend/go-encode-id.h [new file with mode: 0644]
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/types.cc

index 825e4f0..bbae1a9 100644 (file)
@@ -1,3 +1,15 @@
+2016-11-22  Than McIntosh  <thanm@google.com>
+
+       * go-gcc.cc (char_needs_encoding): Remove.
+       (needs_encoding, fetch_utf8_char, encode_id): Remove.
+       (Gcc_backend::global_variable): Add asm_name parameter.  Don't
+       compute asm_name here.
+       (Gcc_backend::implicit_variable): Likewise.
+       (Gcc_backend::implicit_variable_reference): Likewise.
+       (Gcc_backend::immutable_struct): Likewise.
+       (Gcc_backend::immutable_struct_reference): Likewise.
+       * Make-lang.in (GO_OBJS): Add go/go-encode-id.o.
+
 2016-11-22  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (Gcc_backend::Gcc_backend): Add builtin function
index 7235f19..6768330 100644 (file)
@@ -55,6 +55,7 @@ GO_OBJS = \
        go/expressions.o \
        go/go-backend.o \
        go/go-diagnostics.o \
+       go/go-encode-id.o \
        go/go-dump.o \
        go/go-gcc.o \
        go/go-gcc-diagnostics.o \
@@ -230,6 +231,7 @@ CFLAGS-go/go-gcc.o += $(GOINCLUDES)
 CFLAGS-go/go-linemap.o += $(GOINCLUDES)
 CFLAGS-go/go-sha1.o += $(GOINCLUDES)
 CFLAGS-go/go-gcc-diagnostics.o += $(GOINCLUDES)
+CFLAGS-go/go-encode-id.o += $(GOINCLUDES)
 
 go/%.o: go/gofrontend/%.cc
        $(COMPILE) $(GOINCLUDES) $<
index 619499e..dc00413 100644 (file)
@@ -412,9 +412,8 @@ class Gcc_backend : public Backend
   { return new Bvariable(error_mark_node); }
 
   Bvariable*
-  global_variable(const std::string& package_name,
-                 const std::string& pkgpath,
-                 const std::string& name,
+  global_variable(const std::string& var_name,
+                 const std::string& asm_name,
                  Btype* btype,
                  bool is_external,
                  bool is_hidden,
@@ -440,25 +439,27 @@ class Gcc_backend : public Backend
                     Location, Bstatement**);
 
   Bvariable*
-  implicit_variable(const std::string&, Btype*, bool, bool, bool,
-                   int64_t);
+  implicit_variable(const std::string&, const std::string&, Btype*,
+                    bool, bool, bool, int64_t);
 
   void
   implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
                             bool, bool, bool, Bexpression*);
 
   Bvariable*
-  implicit_variable_reference(const std::string&, Btype*);
+  implicit_variable_reference(const std::string&, const std::string&, Btype*);
 
   Bvariable*
-  immutable_struct(const std::string&, bool, bool, Btype*, Location);
+  immutable_struct(const std::string&, const std::string&,
+                   bool, bool, Btype*, Location);
 
   void
   immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*,
                            Location, Bexpression*);
 
   Bvariable*
-  immutable_struct_reference(const std::string&, Btype*, Location);
+  immutable_struct_reference(const std::string&, const std::string&,
+                             Btype*, Location);
 
   // Labels.
 
@@ -550,102 +551,6 @@ get_identifier_from_string(const std::string& str)
   return get_identifier_with_length(str.data(), str.length());
 }
 
-// Return whether the character c is OK to use in the assembler.
-
-static bool
-char_needs_encoding(char c)
-{
-  switch (c)
-    {
-    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
-    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
-    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
-    case 'Y': case 'Z':
-    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
-    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
-    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
-    case 'y': case 'z':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-    case '_': case '.': case '$': case '/':
-      return false;
-    default:
-      return true;
-    }
-}
-
-// Return whether the identifier needs to be translated because it
-// contains non-ASCII characters.
-
-static bool
-needs_encoding(const std::string& str)
-{
-  for (std::string::const_iterator p = str.begin();
-       p != str.end();
-       ++p)
-    if (char_needs_encoding(*p))
-      return true;
-  return false;
-}
-
-// Pull the next UTF-8 character out of P and store it in *PC.  Return
-// the number of bytes read.
-
-static size_t
-fetch_utf8_char(const char* p, unsigned int* pc)
-{
-  unsigned char c = *p;
-  if ((c & 0x80) == 0)
-    {
-      *pc = c;
-      return 1;
-    }
-  size_t len = 0;
-  while ((c & 0x80) != 0)
-    {
-      ++len;
-      c <<= 1;
-    }
-  unsigned int rc = *p & ((1 << (7 - len)) - 1);
-  for (size_t i = 1; i < len; i++)
-    {
-      unsigned int u = p[i];
-      rc <<= 6;
-      rc |= u & 0x3f;
-    }
-  *pc = rc;
-  return len;
-}
-
-// Encode an identifier using ASCII characters.
-
-static std::string
-encode_id(const std::string id)
-{
-  std::string ret;
-  const char* p = id.c_str();
-  const char* pend = p + id.length();
-  while (p < pend)
-    {
-      unsigned int c;
-      size_t len = fetch_utf8_char(p, &c);
-      if (len == 1 && !char_needs_encoding(c))
-       ret += c;
-      else
-       {
-         ret += "$U";
-         char buf[30];
-         snprintf(buf, sizeof buf, "%x", c);
-         ret += buf;
-         ret += "$";
-       }
-      p += len;
-    }
-  return ret;
-}
-
 // Define the built-in functions that are exposed to GCCGo.
 
 Gcc_backend::Gcc_backend()
@@ -2580,9 +2485,8 @@ Gcc_backend::non_zero_size_type(tree type)
 // Make a global variable.
 
 Bvariable*
-Gcc_backend::global_variable(const std::string& package_name,
-                            const std::string& pkgpath,
-                            const std::string& name,
+Gcc_backend::global_variable(const std::string& var_name,
+                            const std::string& asm_name,
                             Btype* btype,
                             bool is_external,
                             bool is_hidden,
@@ -2598,9 +2502,6 @@ Gcc_backend::global_variable(const std::string& package_name,
   if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0)
     type_tree = this->non_zero_size_type(type_tree);
 
-  std::string var_name(package_name);
-  var_name.push_back('.');
-  var_name.append(name);
   tree decl = build_decl(location.gcc_location(), VAR_DECL,
                         get_identifier_from_string(var_name),
                         type_tree);
@@ -2611,17 +2512,12 @@ Gcc_backend::global_variable(const std::string& package_name,
   if (!is_hidden)
     {
       TREE_PUBLIC(decl) = 1;
-
-      std::string asm_name(pkgpath);
-      asm_name.push_back('.');
-      asm_name.append(name);
-      if (needs_encoding(asm_name))
-       asm_name = encode_id(asm_name);
       SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
     }
-  else if (needs_encoding(var_name))
-    SET_DECL_ASSEMBLER_NAME(decl,
-                           get_identifier_from_string(encode_id(var_name)));
+  else
+    {
+      SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+    }
 
   TREE_USED(decl) = 1;
 
@@ -2814,8 +2710,9 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
 // generating GC root variables and storing the values of a slice initializer.
 
 Bvariable*
-Gcc_backend::implicit_variable(const std::string& name, Btype* type,
-                              bool is_hidden, bool is_constant,
+Gcc_backend::implicit_variable(const std::string& name,
+                               const std::string& asm_name,
+                               Btype* type, bool is_hidden, bool is_constant,
                               bool is_common, int64_t alignment)
 {
   tree type_tree = type->get_tree();
@@ -2857,8 +2754,8 @@ Gcc_backend::implicit_variable(const std::string& name, Btype* type,
       SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT);
       DECL_USER_ALIGN(decl) = 1;
     }
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
 
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
@@ -2899,7 +2796,9 @@ Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
 // Return a reference to an implicit variable defined in another package.
 
 Bvariable*
-Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+Gcc_backend::implicit_variable_reference(const std::string& name,
+                                         const std::string& asm_name,
+                                         Btype* btype)
 {
   tree type_tree = btype->get_tree();
   if (type_tree == error_mark_node)
@@ -2911,8 +2810,8 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
   TREE_PUBLIC(decl) = 1;
   TREE_STATIC(decl) = 1;
   DECL_ARTIFICIAL(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
@@ -2920,7 +2819,9 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
 // Create a named immutable initialized data structure.
 
 Bvariable*
-Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
+Gcc_backend::immutable_struct(const std::string& name,
+                              const std::string& asm_name,
+                              bool is_hidden,
                              bool is_common, Btype* btype, Location location)
 {
   tree type_tree = btype->get_tree();
@@ -2937,8 +2838,8 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
   DECL_ARTIFICIAL(decl) = 1;
   if (!is_hidden)
     TREE_PUBLIC(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
 
   // When the initializer for one immutable_struct refers to another,
   // it needs to know the visibility of the referenced struct so that
@@ -2998,7 +2899,9 @@ Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&,
 // defined in another package.
 
 Bvariable*
-Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
+Gcc_backend::immutable_struct_reference(const std::string& name,
+                                        const std::string& asm_name,
+                                        Btype* btype,
                                        Location location)
 {
   tree type_tree = btype->get_tree();
@@ -3013,8 +2916,8 @@ Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
   DECL_ARTIFICIAL(decl) = 1;
   TREE_PUBLIC(decl) = 1;
   DECL_EXTERNAL(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
@@ -3104,10 +3007,8 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     return this->error_function();
 
   tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
-  if (!asm_name.empty())
+  if (! asm_name.empty())
     SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
-  else if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
   if (is_visible)
     TREE_PUBLIC(decl) = 1;
   if (is_declaration)
index 5ff8b8d..fec65b8 100644 (file)
@@ -1,4 +1,4 @@
-e66f30e862cb5d02b9d55bf44ac439bb8fc4ea19
+4d8e00e730897cc7e73b1582522ecab031cfcaf2
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index dacfe48..e93cdfe 100644 (file)
@@ -482,21 +482,19 @@ class Backend
   virtual Bvariable*
   error_variable() = 0;
 
-  // Create a global variable.  PACKAGE_NAME is the name of the
-  // package where the variable is defined.  PKGPATH is the package
-  // path for that package, from the -fgo-pkgpath or -fgo-prefix
-  // option.  NAME is the name of the variable.  BTYPE is the type of
-  // the variable.  IS_EXTERNAL is true if the variable is defined in
-  // some other package.  IS_HIDDEN is true if the variable is not
-  // exported (name begins with a lower case letter).
-  // IN_UNIQUE_SECTION is true if the variable should be put into a
-  // unique section if possible; this is intended to permit the linker
-  // to garbage collect the variable if it is not referenced.
-  // LOCATION is where the variable was defined.
+  // Create a global variable. NAME is the package-qualified name of
+  // the variable.  ASM_NAME is the encoded identifier for the
+  // variable, incorporating the package, and made safe for the
+  // assembler.  BTYPE is the type of the variable.  IS_EXTERNAL is
+  // true if the variable is defined in some other package.  IS_HIDDEN
+  // is true if the variable is not exported (name begins with a lower
+  // case letter).  IN_UNIQUE_SECTION is true if the variable should
+  // be put into a unique section if possible; this is intended to
+  // permit the linker to garbage collect the variable if it is not
+  // referenced.  LOCATION is where the variable was defined.
   virtual Bvariable*
-  global_variable(const std::string& package_name,
-                 const std::string& pkgpath,
-                 const std::string& name,
+  global_variable(const std::string& name,
+                  const std::string& asm_name,
                  Btype* btype,
                  bool is_external,
                  bool is_hidden,
@@ -561,6 +559,9 @@ class Backend
   //
   // NAME is the name to use for the initialized variable this will create.
   //
+  // ASM_NAME is encoded assembler-friendly version of the name, or the
+  // empty string if no encoding is needed.
+  //
   // TYPE is the type of the implicit variable. 
   //
   // IS_HIDDEN will be true if the descriptor should only be visible
@@ -578,8 +579,9 @@ class Backend
   //
   // If ALIGNMENT is not zero, it is the desired alignment of the variable.
   virtual Bvariable*
-  implicit_variable(const std::string& name, Btype* type, bool is_hidden,
-                   bool is_constant, bool is_common, int64_t alignment) = 0;
+  implicit_variable(const std::string& name, const std::string& asm_name,
+                    Btype* type, bool is_hidden, bool is_constant,
+                    bool is_common, int64_t alignment) = 0;
 
 
   // Set the initial value of a variable created by implicit_variable.
@@ -597,12 +599,15 @@ class Backend
                             bool is_hidden, bool is_constant, bool is_common,
                             Bexpression* init) = 0;
 
-  // Create a reference to a named implicit variable defined in some other
-  // package.  This will be a variable created by a call to implicit_variable
-  // with the same NAME and TYPE and with IS_COMMON passed as false.  This
-  // corresponds to an extern global variable in C.
+  // Create a reference to a named implicit variable defined in some
+  // other package.  This will be a variable created by a call to
+  // implicit_variable with the same NAME, ASM_NAME and TYPE and with
+  // IS_COMMON passed as false.  This corresponds to an extern global
+  // variable in C.
   virtual Bvariable*
-  implicit_variable_reference(const std::string& name, Btype* type) = 0;
+  implicit_variable_reference(const std::string& name,
+                              const std::string& asm_name,
+                              Btype* type) = 0;
 
   // Create a named immutable initialized data structure.  This is
   // used for type descriptors, map descriptors, and function
@@ -612,6 +617,9 @@ class Backend
   // NAME is the name to use for the initialized global variable which
   // this call will create.
   //
+  // ASM_NAME is the encoded, assembler-friendly version of NAME, or
+  // the empty string if no encoding is needed.
+  //
   // IS_HIDDEN will be true if the descriptor should only be visible
   // within the current object.
   //
@@ -630,7 +638,9 @@ class Backend
   // address.  After calling this the frontend will call
   // immutable_struct_set_init.
   virtual Bvariable*
-  immutable_struct(const std::string& name, bool is_hidden, bool is_common,
+  immutable_struct(const std::string& name,
+                   const std::string& asm_name,
+                   bool is_hidden, bool is_common,
                   Btype* type, Location) = 0;
 
   // Set the initial value of a variable created by immutable_struct.
@@ -648,11 +658,12 @@ class Backend
   // Create a reference to a named immutable initialized data
   // structure defined in some other package.  This will be a
   // structure created by a call to immutable_struct with the same
-  // NAME and TYPE and with IS_COMMON passed as false.  This
+  // NAME, ASM_NAME and TYPE and with IS_COMMON passed as false.  This
   // corresponds to an extern const global variable in C.
   virtual Bvariable*
-  immutable_struct_reference(const std::string& name, Btype* type,
-                            Location) = 0;
+  immutable_struct_reference(const std::string& name,
+                             const std::string& asm_name,
+                             Btype* type, Location) = 0;
 
   // Labels.
   
index 35c3e74..0ab6726 100644 (file)
@@ -11,6 +11,7 @@
 #include "go-c.h"
 #include "gogo.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "types.h"
 #include "export.h"
 #include "import.h"
@@ -1304,16 +1305,18 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
   Btype* btype = this->type()->get_backend(gogo);
 
   Bvariable* bvar;
+  std::string asm_name(go_selectively_encode_id(var_name));
   if (no->package() != NULL || is_descriptor)
-    bvar = context->backend()->immutable_struct_reference(var_name, btype,
-                                                         loc);
+    bvar = context->backend()->immutable_struct_reference(var_name, asm_name,
+                                                          btype, loc);
   else
     {
       Location bloc = Linemap::predeclared_location();
       bool is_hidden = ((no->is_function()
                         && no->func_value()->enclosing() != NULL)
                        || Gogo::is_thunk(no));
-      bvar = context->backend()->immutable_struct(var_name, is_hidden, false,
+      bvar = context->backend()->immutable_struct(var_name, asm_name,
+                                                  is_hidden, false,
                                                  btype, bloc);
       Expression_list* vals = new Expression_list();
       vals->push_back(Expression::make_func_code_reference(this->fn_, bloc));
@@ -4283,9 +4286,11 @@ Unary_expression::do_get_backend(Translate_context* context)
              // 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));
          Bvariable* implicit =
-           gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
-                                              false, 0);
+              gogo->backend()->implicit_variable(buf, asm_name,
+                                                 btype, true, copy_to_heap,
+                                                 false, 0);
          gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
                                                      true, copy_to_heap, false,
                                                      bexpr);
@@ -4299,8 +4304,10 @@ Unary_expression::do_get_backend(Translate_context* context)
           snprintf(buf, sizeof buf, "C%u", counter);
           ++counter;
 
+          std::string asm_name(go_selectively_encode_id(buf));
           Bvariable* decl =
-              gogo->backend()->immutable_struct(buf, true, false, btype, loc);
+              gogo->backend()->immutable_struct(buf, asm_name,
+                                                true, false, btype, loc);
           gogo->backend()->immutable_struct_set_init(decl, buf, true, false,
                                                      btype, loc, bexpr);
           bexpr = gogo->backend()->var_expression(decl, loc);
@@ -15074,8 +15081,10 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
       && this->type_->named_type()->named_object()->package() != NULL)
     {
       Btype* btype = this->type()->get_backend(gogo);
+      std::string asm_name(go_selectively_encode_id(mangled_name));
       this->bvar_ =
-          gogo->backend()->immutable_struct_reference(mangled_name, btype, loc);
+          gogo->backend()->immutable_struct_reference(mangled_name, asm_name,
+                                                      btype, loc);
       return gogo->backend()->var_expression(this->bvar_, this->location());
     }
 
@@ -15119,7 +15128,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
   Bexpression* ctor = mtable->get_backend(context);
 
   bool is_public = has_hidden_methods && this->type_->named_type() != NULL;
-  this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false,
+  std::string asm_name(go_selectively_encode_id(mangled_name));
+  this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false,
                                                  !is_public, btype, loc);
   gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
                                              !is_public, btype, loc, ctor);
diff --git a/gcc/go/gofrontend/go-encode-id.cc b/gcc/go/gofrontend/go-encode-id.cc
new file mode 100644 (file)
index 0000000..978f208
--- /dev/null
@@ -0,0 +1,113 @@
+// go-encode-id.cc -- Go identifier encoding hooks
+
+// Copyright 2016 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-location.h"
+#include "go-linemap.h"
+#include "go-encode-id.h"
+
+// Return whether the character c is OK to use in the assembler.
+
+static bool
+char_needs_encoding(char c)
+{
+  switch (c)
+    {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case '_': case '.': case '$': case '/':
+      return false;
+    default:
+      return true;
+    }
+}
+
+// Return whether the identifier needs to be translated because it
+// contains non-ASCII characters.
+
+bool
+go_id_needs_encoding(const std::string& str)
+{
+  for (std::string::const_iterator p = str.begin();
+       p != str.end();
+       ++p)
+    if (char_needs_encoding(*p))
+      return true;
+  return false;
+}
+
+// Pull the next UTF-8 character out of P and store it in *PC.  Return
+// the number of bytes read.
+
+static size_t
+fetch_utf8_char(const char* p, unsigned int* pc)
+{
+  unsigned char c = *p;
+  if ((c & 0x80) == 0)
+    {
+      *pc = c;
+      return 1;
+    }
+  size_t len = 0;
+  while ((c & 0x80) != 0)
+    {
+      ++len;
+      c <<= 1;
+    }
+  unsigned int rc = *p & ((1 << (7 - len)) - 1);
+  for (size_t i = 1; i < len; i++)
+    {
+      unsigned int u = p[i];
+      rc <<= 6;
+      rc |= u & 0x3f;
+    }
+  *pc = rc;
+  return len;
+}
+
+// Encode an identifier using ASCII characters.
+
+std::string
+go_encode_id(const std::string &id)
+{
+  std::string ret;
+  const char* p = id.c_str();
+  const char* pend = p + id.length();
+  while (p < pend)
+    {
+      unsigned int c;
+      size_t len = fetch_utf8_char(p, &c);
+      if (len == 1 && !char_needs_encoding(c))
+        ret += c;
+      else
+        {
+          ret += "$U";
+          char buf[30];
+          snprintf(buf, sizeof buf, "%x", c);
+          ret += buf;
+          ret += "$";
+        }
+      p += len;
+    }
+  return ret;
+}
+
+std::string
+go_selectively_encode_id(const std::string &id)
+{
+  if (go_id_needs_encoding(id))
+    return go_encode_id(id);
+  return std::string();
+}
diff --git a/gcc/go/gofrontend/go-encode-id.h b/gcc/go/gofrontend/go-encode-id.h
new file mode 100644 (file)
index 0000000..b95d97d
--- /dev/null
@@ -0,0 +1,30 @@
+// go-encode-id.h -- Go identifier encoding utilities  -*- C++ -*-
+
+// Copyright 2016 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.
+
+#ifndef GO_ENCODE_ID_H
+#define GO_ENCODE_ID_H
+
+#include "backend.h"
+
+// Given an identifier corresponding to a function or variable,
+// this helper returns TRUE if the identifier needs special
+// encoding to be used as an ASM name (symbol), FALSE if the name
+// is OK as is.
+extern bool
+go_id_needs_encoding(const std::string& str);
+
+// Encodes the specified identifier for ASM name safety, returning a
+// string with the encoded value.
+extern std::string
+go_encode_id(const std::string &id);
+
+// Returns the empty string if the specified name needs encoding,
+// otherwise invokes go_encode_id() on the name and returns the
+// result.
+extern std::string
+go_selectively_encode_id(const std::string &id);
+
+#endif // !defined(GO_ENCODE_ID_H)
index a9dd0a6..b671ce5 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "go-c.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "go-dump.h"
 #include "go-optimize.h"
 #include "lex.h"
@@ -5326,6 +5327,10 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
       if ((this->pragmas_ & GOPRAGMA_NOSPLIT) != 0)
        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));
+
       // This should go into a unique section if that has been
       // requested elsewhere, or if this is a nointerface function.
       // We want to put a nointerface function into a unique section
@@ -5379,6 +5384,8 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
               asm_name.append(rtype->mangled_name(gogo));
             }
         }
+      else if (go_id_needs_encoding(no->get_id(gogo)))
+        asm_name = go_encode_id(no->get_id(gogo));
 
       Btype* functype = this->fntype_->get_backend_fntype(gogo);
       this->fndecl_ =
@@ -6594,25 +6601,39 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
              type = Type::make_pointer_type(type);
            }
 
-         std::string n = Gogo::unpack_hidden_name(name);
+         const std::string n = Gogo::unpack_hidden_name(name);
          Btype* btype = type->get_backend(gogo);
 
          Bvariable* bvar;
          if (Map_type::is_zero_value(this))
            bvar = Map_type::backend_zero_value(gogo);
          else if (this->is_global_)
-           bvar = backend->global_variable((package == NULL
-                                            ? gogo->package_name()
-                                            : package->package_name()),
-                                           (package == NULL
-                                            ? gogo->pkgpath_symbol()
-                                            : package->pkgpath_symbol()),
-                                           n,
-                                           btype,
-                                           package != NULL,
-                                           Gogo::is_hidden_name(name),
-                                           this->in_unique_section_,
-                                           this->location_);
+           {
+             std::string var_name(package != NULL
+                                  ? package->package_name()
+                                  : 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);
+             bvar = backend->global_variable(var_name,
+                                             asm_name,
+                                             btype,
+                                             package != NULL,
+                                             Gogo::is_hidden_name(name),
+                                             this->in_unique_section_,
+                                             this->location_);
+           }
          else if (function == NULL)
            {
              go_assert(saw_errors());
index bc6e3c6..33d3460 100644 (file)
@@ -11,6 +11,7 @@
 #include "go-c.h"
 #include "gogo.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "operator.h"
 #include "expressions.h"
 #include "statements.h"
@@ -1217,10 +1218,12 @@ Type::make_type_descriptor_var(Gogo* gogo)
 
       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 asm_name(go_selectively_encode_id(name));
       this->type_descriptor_var_ =
-       gogo->backend()->immutable_struct_reference("__go_tdn_unsafe.Pointer",
-                                                   td_btype,
-                                                   bloc);
+         gogo->backend()->immutable_struct_reference(name, asm_name,
+                                                     td_btype,
+                                                     bloc);
 
       if (phash != NULL)
        *phash = this->type_descriptor_var_;
@@ -1239,10 +1242,11 @@ Type::make_type_descriptor_var(Gogo* gogo)
   const Package* dummy;
   if (this->type_descriptor_defined_elsewhere(nt, &dummy))
     {
+      std::string asm_name(go_selectively_encode_id(var_name));
       this->type_descriptor_var_ =
-       gogo->backend()->immutable_struct_reference(var_name,
-                                                   initializer_btype,
-                                                   loc);
+         gogo->backend()->immutable_struct_reference(var_name, asm_name,
+                                                     initializer_btype,
+                                                     loc);
       if (phash != NULL)
        *phash = this->type_descriptor_var_;
       return;
@@ -1271,8 +1275,9 @@ Type::make_type_descriptor_var(Gogo* gogo)
   // ensure that type_descriptor_pointer will work if called while
   // converting INITIALIZER.
 
+  std::string asm_name(go_selectively_encode_id(var_name));
   this->type_descriptor_var_ =
-    gogo->backend()->immutable_struct(var_name, false, is_common,
+      gogo->backend()->immutable_struct(var_name, asm_name, false, is_common,
                                      initializer_btype, loc);
   if (phash != NULL)
     *phash = this->type_descriptor_var_;
@@ -2187,8 +2192,10 @@ Type::make_gc_symbol_var(Gogo* gogo)
   const Package* dummy;
   if (this->type_descriptor_defined_elsewhere(nt, &dummy))
     {
+      std::string asm_name(go_selectively_encode_id(sym_name));
       this->gc_symbol_var_ =
-       gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
+          gogo->backend()->implicit_variable_reference(sym_name, asm_name,
+                                                       sym_btype);
       if (phash != NULL)
        *phash = this->gc_symbol_var_;
       return;
@@ -2213,8 +2220,10 @@ Type::make_gc_symbol_var(Gogo* gogo)
   // Since we are building the GC symbol in this package, we must create the
   // variable before converting the initializer to its backend representation
   // because the initializer may refer to the GC symbol for this type.
+  std::string asm_name(go_selectively_encode_id(sym_name));
   this->gc_symbol_var_ =
-    gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
+      gogo->backend()->implicit_variable(sym_name, asm_name,
+                                         sym_btype, false, true, is_common, 0);
   if (phash != NULL)
     *phash = this->gc_symbol_var_;
 
@@ -7034,8 +7043,10 @@ Map_type::backend_zero_value(Gogo* gogo)
   Btype* barray_type = gogo->backend()->array_type(buint8_type, blength);
 
   std::string zname = Map_type::zero_value->name();
+  std::string asm_name(go_selectively_encode_id(zname));
   Bvariable* zvar =
-    gogo->backend()->implicit_variable(zname, barray_type, false, true, true,
+      gogo->backend()->implicit_variable(zname, asm_name,
+                                         barray_type, false, true, true,
                                       Map_type::zero_value_align);
   gogo->backend()->implicit_variable_set_init(zvar, zname, barray_type,
                                              false, true, true, NULL);