This patch to the Go frontend encodes user visible names if necessary.
We already encode the assembler names.  With this patch, we also avoid
putting weird characters into the user visible name.  Doing so breaks
stabs debugging in particular, and may also cause debugger problems.
Instead, we encode those names, and use a "g." prefix to tell the
debugger (no debugger knows about this convention, but it's there for
potential future use).

Also dereference the type for the name of a recover thunk, to avoid a
pointless '*' that gets encoded.

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

Ian
04781b14ca5ab74711a73de923056357b6a02faf
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index dc2682d95d1..681debb0392 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-0d0b423739b2fee9788cb6cb8af9ced29375e545
+3e8f49a2137a87fdaba51c3002ddbe41ab18ed46
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index f22d47656db..49d7bd9b98a 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -67,7 +67,7 @@ class Backend_name
  public:
   Backend_name()
     : prefix_(NULL), components_(), count_(0), suffix_(),
-      is_asm_name_(false)
+      is_asm_name_(false), is_non_identifier_(false)
   {}
 
   // Set the prefix.  Prefixes are always constant strings.
@@ -120,6 +120,18 @@ class Backend_name
     this->is_asm_name_ = true;
   }
 
+  // Whether some component includes some characters that can't appear
+  // in an identifier.
+  bool
+  is_non_identifier() const
+  { return this->is_non_identifier_; }
+
+  // Record that some component includes some character that can't
+  // appear in an identifier.
+  void
+  set_is_non_identifier()
+  { this->is_non_identifier_ = true; }
+
   // Get the user visible name.
   std::string
   name() const;
@@ -150,6 +162,9 @@ class Backend_name
   std::string suffix_;
   // True if components_[0] is an assembler name specified by the user.
   bool is_asm_name_;
+  // True if some component includes some character that can't
+  // normally appear in an identifier.
+  bool is_non_identifier_;
 };
 
 // An initialization function for an imported package.  This is a
diff --git a/gcc/go/gofrontend/names.cc b/gcc/go/gofrontend/names.cc
index 8e73e5e157c..f85d84ceadf 100644
--- a/gcc/go/gofrontend/names.cc
+++ b/gcc/go/gofrontend/names.cc
@@ -186,6 +186,20 @@
 // 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
@@ -512,7 +526,7 @@ Gogo::recover_thunk_name(const std::string& name, const 
Type* rtype)
   if (rtype != NULL)
     {
       Backend_name bname;
-      rtype->backend_name(this, &bname);
+      rtype->deref()->backend_name(this, &bname);
       ret = bname.name();
       ret.append(1, '.');
     }
@@ -634,37 +648,45 @@ Type::backend_name(Gogo* gogo, Backend_name* bname) const
     }
 
   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);
+  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) const
+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) const
+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) const
+Boolean_type::do_mangled_name(Gogo*, std::string* ret, bool*) const
 {
   ret->append("bool");
 }
 
 void
-Integer_type::do_mangled_name(Gogo*, std::string* ret) const
+Integer_type::do_mangled_name(Gogo*, std::string* ret,
+                             bool* is_non_identifier) const
 {
   char buf[100];
   snprintf(buf, sizeof buf, "%s%si%d",
@@ -672,43 +694,53 @@ Integer_type::do_mangled_name(Gogo*, std::string* ret) 
const
           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) const
+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) const
+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) const
+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) const
+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);
+      this->append_mangled_name(this->receiver_->type(), gogo, ret,
+                               is_non_identifier);
       ret->append(")");
     }
 
@@ -727,7 +759,8 @@ Function_type::do_mangled_name(Gogo* gogo, std::string* 
ret) const
            ret->push_back(',');
          if (this->is_varargs_ && p + 1 == params->end())
            ret->append("...");
-         this->append_mangled_name(p->type(), gogo, ret);
+         this->append_mangled_name(p->type(), gogo, ret,
+                                   is_non_identifier);
        }
     }
   ret->push_back(')');
@@ -745,27 +778,34 @@ Function_type::do_mangled_name(Gogo* gogo, std::string* 
ret) const
            first = false;
          else
            ret->append(",");
-         this->append_mangled_name(p->type(), gogo, ret);
+         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) const
+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);
+  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) const
+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) const
+Struct_type::do_mangled_name(Gogo* gogo, std::string* ret,
+                            bool* is_non_identifier) const
 {
   ret->append("struct{");
 
@@ -796,9 +836,10 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) 
const
          if (p->is_anonymous()
              && p->type()->named_type() != NULL
              && p->type()->named_type()->is_alias())
-           p->type()->named_type()->append_symbol_type_name(gogo, true, ret);
+           p->type()->named_type()->append_symbol_type_name(gogo, true, ret,
+                                                            is_non_identifier);
          else
-           this->append_mangled_name(p->type(), gogo, ret);
+           this->append_mangled_name(p->type(), gogo, ret, is_non_identifier);
 
          if (p->has_tag())
            {
@@ -813,10 +854,13 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* 
ret) const
     }
 
   ret->push_back('}');
+
+  *is_non_identifier = true;
 }
 
 void
-Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+Array_type::do_mangled_name(Gogo* gogo, std::string* ret,
+                           bool* is_non_identifier) const
 {
   ret->push_back('[');
   if (this->length_ != NULL)
@@ -841,20 +885,24 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) 
const
        ret->append("x");
     }
   ret->push_back(']');
-  this->append_mangled_name(this->element_type_, gogo, ret);
+  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) const
+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);
+  this->append_mangled_name(this->key_type_, gogo, ret, is_non_identifier);
   ret->push_back(']');
-  this->append_mangled_name(this->val_type_, gogo, ret);
+  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) const
+Channel_type::do_mangled_name(Gogo* gogo, std::string* ret,
+                             bool* is_non_identifier) const
 {
   if (!this->may_send_)
     ret->append("<-");
@@ -862,11 +910,13 @@ Channel_type::do_mangled_name(Gogo* gogo, std::string* 
ret) const
   if (!this->may_receive_)
     ret->append("<-");
   ret->push_back(' ');
-  this->append_mangled_name(this->element_type_, gogo, ret);
+  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) const
+Interface_type::do_mangled_name(Gogo* gogo, std::string* ret,
+                               bool* is_non_identifier) const
 {
   go_assert(this->methods_are_finalized_);
 
@@ -892,25 +942,29 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* 
ret) const
              ret->push_back(' ');
            }
 
-         this->append_mangled_name(p->type(), gogo, ret);
+         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) const
+Named_type::do_mangled_name(Gogo* gogo, std::string* ret,
+                           bool* is_non_identifier) const
 {
-  this->append_symbol_type_name(gogo, false, ret);
+  this->append_symbol_type_name(gogo, false, ret, is_non_identifier);
 }
 
 void
-Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+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);
+    this->append_mangled_name(this->real_type(), gogo, ret, is_non_identifier);
   else
     {
       const Named_object* no = this->named_object();
@@ -929,7 +983,8 @@ Forward_declaration_type::do_mangled_name(Gogo* gogo, 
std::string* ret) const
 
 void
 Named_type::append_symbol_type_name(Gogo* gogo, bool use_alias,
-                                   std::string* ret) const
+                                   std::string* ret,
+                                   bool* is_non_identifier) const
 {
   if (this->is_error_)
     return;
@@ -938,7 +993,7 @@ Named_type::append_symbol_type_name(Gogo* gogo, bool 
use_alias,
       if (this->seen_alias_)
        return;
       this->seen_alias_ = true;
-      this->append_mangled_name(this->type_, gogo, ret);
+      this->append_mangled_name(this->type_, gogo, ret, is_non_identifier);
       this->seen_alias_ = false;
       return;
     }
@@ -957,6 +1012,8 @@ Named_type::append_symbol_type_name(Gogo* gogo, bool 
use_alias,
              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());
@@ -1160,6 +1217,15 @@ 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_);
@@ -1203,6 +1269,8 @@ 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();
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index d2741f6db58..f9097d5e130 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -4602,7 +4602,7 @@ class Sink_type : public Type
   { go_unreachable(); }
 
   void
-  do_mangled_name(Gogo*, std::string*) const
+  do_mangled_name(Gogo*, std::string*, bool*) const
   { go_unreachable(); }
 };
 
@@ -5712,7 +5712,7 @@ class Call_multiple_result_type : public Type
   { go_assert(saw_errors()); }
 
   void
-  do_mangled_name(Gogo*, std::string*) const
+  do_mangled_name(Gogo*, std::string*, bool*) const
   { go_assert(saw_errors()); }
 
  private:
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index b7dd391d321..f2880f9c5d8 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1140,7 +1140,7 @@ class Type
   do_reflection(Gogo*, std::string*) const = 0;
 
   virtual void
-  do_mangled_name(Gogo*, std::string*) const = 0;
+  do_mangled_name(Gogo*, std::string*, bool*) const = 0;
 
   virtual void
   do_export(Export*) const;
@@ -1202,8 +1202,9 @@ class Type
 
   // For the benefit of child class mangling.
   void
-  append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const
-  { type->do_mangled_name(gogo, ret); }
+  append_mangled_name(const Type* type, Gogo* gogo, std::string* ret,
+                     bool *is_non_identifier) const
+  { type->do_mangled_name(gogo, ret, is_non_identifier); }
 
   // Return the backend representation for the underlying type of a
   // named type.
@@ -1664,7 +1665,7 @@ class Error_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 };
 
 // The void type.
@@ -1693,7 +1694,7 @@ class Void_type : public Type
   { }
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 };
 
 // The boolean type.
@@ -1722,7 +1723,7 @@ class Boolean_type : public Type
   { ret->append("bool"); }
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 };
 
 // The type of an integer.
@@ -1808,7 +1809,7 @@ protected:
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
  private:
   Integer_type(bool is_abstract, bool is_unsigned, int bits,
@@ -1894,7 +1895,7 @@ class Float_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
  private:
   Float_type(bool is_abstract, int bits, int runtime_type_kind)
@@ -1972,7 +1973,7 @@ class Complex_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
  private:
   Complex_type(bool is_abstract, int bits, int runtime_type_kind)
@@ -2026,7 +2027,7 @@ class String_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
  private:
   // The named string type.
@@ -2186,7 +2187,7 @@ class Function_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -2315,7 +2316,7 @@ class Pointer_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -2353,7 +2354,7 @@ class Nil_type : public Type
   { go_unreachable(); }
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 };
 
 // The type of a field in a struct.
@@ -2687,7 +2688,7 @@ class Struct_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -2870,7 +2871,7 @@ class Array_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -3008,7 +3009,7 @@ class Map_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -3122,7 +3123,7 @@ class Channel_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -3298,7 +3299,7 @@ class Interface_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string*) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -3572,7 +3573,8 @@ class Named_type : public Type
   // Append the symbol type name as for Type::append_mangled_name,
   // but if USE_ALIAS use the alias name rather than the alias target.
   void
-  append_symbol_type_name(Gogo*, bool use_alias, std::string*) const;
+  append_symbol_type_name(Gogo*, bool use_alias, std::string*,
+                         bool* is_non_identifier) const;
 
   // Import a named type.
   static void
@@ -3619,7 +3621,7 @@ class Named_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;
@@ -3783,7 +3785,7 @@ class Forward_declaration_type : public Type
   do_reflection(Gogo*, std::string*) const;
 
   void
-  do_mangled_name(Gogo*, std::string* ret) const;
+  do_mangled_name(Gogo*, std::string*, bool*) const;
 
   void
   do_export(Export*) const;

Reply via email to