[RFA] Use rust_demangle

Message ID 20170418123111.11785-1-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey April 18, 2017, 12:31 p.m. UTC
  PR rust/20268 is about using the extra Rust-specific demangling that
was added to libiberty.

Initially this looked easy: just change rust_language_defn to
reference rust_demangle.  However, it's not quite so simple:

* Writing a "real" test was tricky because some bugs in the Rust
  compiler cause gdb to pick funny names for the affected functions,
  and when debuginfo is available it's hard to access the minsyms.
  This I fixed by adding a comment and compiling without debuginfo.

* This revealed a couple of spots in symtab.c where gdb wasn't
  checking for language_rust.

* The C++ demangler runs before the Rust demangler.  And, because the
  Rust mangling scheme is C++-like, Rust symbols will never be seen by
  the Rust demangler.  The fix is to have the C++ demangler return
  NULL for Rust symbols.

* ... but that affects some tests cases, like demangle.exp, because
  gdb then need special treatment for DMGL_AUTO.

* ... and, in light of this change, "set demangle-style" seems a bit
  weird because it allows the setting of styles to things obviously
  not related to C++ at all, hence a change in demangle.c.

Two future ideas came to mind.  One is to remove obsolete things like
the Lucide demangling style.  The other is to change the demangler's
"auto" mode to also return the language of the symbol, if it could be
discovered.  This would avoid double demangling.

Built and regtested on the buildbot.

ChangeLog
2017-04-16  Tom Tromey  <tom@tromey.com>

	PR rust/20268:
	* demangle.c (_initialize_demangler): Filter out non-C++ styles.
	* symtab.c (symbol_natural_name, symbol_demangled_name): Demangle
	for language_rust.
	* cp-support.h (gdb_demangle_cxx): Declare.
	* cp-support.c (gdb_demangle_cxx): New function.
	(gdb_sniff_from_mangled_name): Use it.
	* c-lang.c (cplus_language_defn): Reference gdb_demangle_cxx.
	* rust-lang.c (rust_sniff_from_mangled_name): Call rust_demangle.
	(rust_language_defn): Reference rust_demangle.

testsuite/ChangeLog
2017-04-14  Tom Tromey  <tom@tromey.com>

	PR rust/20268:
	* gdb.rust/rdemangle.exp: New file.
	* gdb.rust/rdemangle.rs: New file.
---
 gdb/ChangeLog                        | 13 +++++++++++
 gdb/c-lang.c                         |  2 +-
 gdb/cp-support.c                     | 23 ++++++++++++++++++-
 gdb/cp-support.h                     |  8 ++++++-
 gdb/demangle.c                       | 36 ++++++++++++++++++++----------
 gdb/rust-lang.c                      |  4 ++--
 gdb/symtab.c                         |  2 ++
 gdb/testsuite/ChangeLog              |  6 +++++
 gdb/testsuite/gdb.rust/rdemangle.exp | 39 ++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.rust/rdemangle.rs  | 43 ++++++++++++++++++++++++++++++++++++
 10 files changed, 159 insertions(+), 17 deletions(-)
 create mode 100644 gdb/testsuite/gdb.rust/rdemangle.exp
 create mode 100644 gdb/testsuite/gdb.rust/rdemangle.rs
  

Comments

Simon Marchi April 22, 2017, 3:52 a.m. UTC | #1
On 2017-04-18 08:31, Tom Tromey wrote:
> PR rust/20268 is about using the extra Rust-specific demangling that
> was added to libiberty.

It looks like you got the wrong PR number, I think it should be 20367.

> Initially this looked easy: just change rust_language_defn to
> reference rust_demangle.  However, it's not quite so simple:

There are many things packed in a single patch, I think they would each 
deserve more explanation so that non-rusters can understand.

> * Writing a "real" test was tricky because some bugs in the Rust
>   compiler cause gdb to pick funny names for the affected functions,
>   and when debuginfo is available it's hard to access the minsyms.
>   This I fixed by adding a comment and compiling without debuginfo.
> 
> * This revealed a couple of spots in symtab.c where gdb wasn't
>   checking for language_rust.
> 
> * The C++ demangler runs before the Rust demangler.  And, because the
>   Rust mangling scheme is C++-like, Rust symbols will never be seen by
>   the Rust demangler.  The fix is to have the C++ demangler return
>   NULL for Rust symbols.

Here for example, could you provide an example of when things go wrong 
(a Rust symbol wrongfully demangled as a C++ symbol)?

> * ... but that affects some tests cases, like demangle.exp, because
>   gdb then need special treatment for DMGL_AUTO.
> 
> * ... and, in light of this change, "set demangle-style" seems a bit
>   weird because it allows the setting of styles to things obviously
>   not related to C++ at all, hence a change in demangle.c.

If other languages have mangling too, why shouldn't we be able to set 
the mangling to that style?  For example, why shouldn't we be able to do 
"set demangle-style rust"?

> Two future ideas came to mind.  One is to remove obsolete things like
> the Lucide demangling style.  The other is to change the demangler's
> "auto" mode to also return the language of the symbol, if it could be
> discovered.  This would avoid double demangling.
> 
> Built and regtested on the buildbot.
> 
> ChangeLog
> 2017-04-16  Tom Tromey  <tom@tromey.com>
> 
> 	PR rust/20268:
> 	* demangle.c (_initialize_demangler): Filter out non-C++ styles.
> 	* symtab.c (symbol_natural_name, symbol_demangled_name): Demangle
> 	for language_rust.
> 	* cp-support.h (gdb_demangle_cxx): Declare.
> 	* cp-support.c (gdb_demangle_cxx): New function.
> 	(gdb_sniff_from_mangled_name): Use it.
> 	* c-lang.c (cplus_language_defn): Reference gdb_demangle_cxx.
> 	* rust-lang.c (rust_sniff_from_mangled_name): Call rust_demangle.
> 	(rust_language_defn): Reference rust_demangle.
> 
> testsuite/ChangeLog
> 2017-04-14  Tom Tromey  <tom@tromey.com>
> 
> 	PR rust/20268:
> 	* gdb.rust/rdemangle.exp: New file.
> 	* gdb.rust/rdemangle.rs: New file.
> ---
>  gdb/ChangeLog                        | 13 +++++++++++
>  gdb/c-lang.c                         |  2 +-
>  gdb/cp-support.c                     | 23 ++++++++++++++++++-
>  gdb/cp-support.h                     |  8 ++++++-
>  gdb/demangle.c                       | 36 
> ++++++++++++++++++++----------
>  gdb/rust-lang.c                      |  4 ++--
>  gdb/symtab.c                         |  2 ++
>  gdb/testsuite/ChangeLog              |  6 +++++
>  gdb/testsuite/gdb.rust/rdemangle.exp | 39 
> ++++++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.rust/rdemangle.rs  | 43 
> ++++++++++++++++++++++++++++++++++++
>  10 files changed, 159 insertions(+), 17 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.rust/rdemangle.exp
>  create mode 100644 gdb/testsuite/gdb.rust/rdemangle.rs
> 
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index f033ced..a96507a 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,16 @@
> +2017-04-16  Tom Tromey  <tom@tromey.com>
> +
> +	PR rust/20268:
> +	* demangle.c (_initialize_demangler): Filter out non-C++ styles.
> +	* symtab.c (symbol_natural_name, symbol_demangled_name): Demangle
> +	for language_rust.
> +	* cp-support.h (gdb_demangle_cxx): Declare.
> +	* cp-support.c (gdb_demangle_cxx): New function.
> +	(gdb_sniff_from_mangled_name): Use it.
> +	* c-lang.c (cplus_language_defn): Reference gdb_demangle_cxx.
> +	* rust-lang.c (rust_sniff_from_mangled_name): Call rust_demangle.
> +	(rust_language_defn): Reference rust_demangle.
> +
>  2017-04-17  Joel Brobecker  <brobecker@adacore.com>
> 
>  	* NEWS: Create a new section for the next release branch.
> diff --git a/gdb/c-lang.c b/gdb/c-lang.c
> index 19a8608..874916e 100644
> --- a/gdb/c-lang.c
> +++ b/gdb/c-lang.c
> @@ -995,7 +995,7 @@ const struct language_defn cplus_language_defn =
>    "this",                       /* name_of_this */
>    cp_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
>    cp_lookup_transparent_type,   /* lookup_transparent_type */
> -  gdb_demangle,			/* Language specific symbol demangler */
> +  gdb_demangle_cxx,	        /* Language specific symbol demangler */

Should it be called cp_demangle for consistency?

>    gdb_sniff_from_mangled_name,
>    cp_class_name_from_physname,  /* Language specific
>  				   class_name_from_physname */
> diff --git a/gdb/cp-support.c b/gdb/cp-support.c
> index 5704466..1a86532 100644
> --- a/gdb/cp-support.c
> +++ b/gdb/cp-support.c
> @@ -1588,10 +1588,31 @@ gdb_demangle (const char *name, int options)
> 
>  /* See cp-support.h.  */
> 
> +char *
> +gdb_demangle_cxx (const char *mangled, int options)
> +{
> +  int style = (DMGL_GNU | DMGL_LUCID | DMGL_ARM
> +	       | DMGL_HP | DMGL_EDG | DMGL_GNU_V3);
> +
> +  if ((current_demangling_style & DMGL_AUTO) == 0)
> +    style &= current_demangling_style;

This deserves a comment, what does it accomplish?  Restrict the style to 
a restricted set of styles?

> +
> +  char *ret = gdb_demangle (mangled, (options | DMGL_PARAMS | 
> DMGL_ANSI
> +				      | style));
> +  if (rust_is_mangled (ret))
> +    {
> +      xfree (ret);
> +      ret = NULL;
> +    }

The reference to rust here looks strange enough that it deserves a 
comment.

> +  return ret;
> +}
> +
> +/* See cp-support.h.  */
> +
>  int
>  gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
>  {
> -  *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
> +  *demangled = gdb_demangle_cxx (mangled, 0);
>    return *demangled != NULL;
>  }
> 
> diff --git a/gdb/cp-support.h b/gdb/cp-support.h
> index 9054bf6..aaca67e 100644
> --- a/gdb/cp-support.h
> +++ b/gdb/cp-support.h
> @@ -157,7 +157,13 @@ extern struct cmd_list_element 
> *maint_cplus_cmd_list;
> 
>  char *gdb_demangle (const char *name, int options);
> 
> -/* Like gdb_demangle, but suitable for use as 
> la_sniff_from_mangled_name.  */
> +/* A wrapper for gdb_demangle that will only successfully demangle C++
> +   names.  */
> +
> +char *gdb_demangle_cxx (const char *mangled, int options);
> +
> +/* Like gdb_demangle_cxx, but suitable for use as
> +   la_sniff_from_mangled_name.  */
> 
>  int gdb_sniff_from_mangled_name (const char *mangled, char 
> **demangled);
> 
> diff --git a/gdb/demangle.c b/gdb/demangle.c
> index 2d79c1d..d9ed896 100644
> --- a/gdb/demangle.c
> +++ b/gdb/demangle.c
> @@ -232,25 +232,37 @@ extern initialize_file_ftype
> _initialize_demangler; /* -Wmissing-prototypes */
>  void
>  _initialize_demangler (void)
>  {
> -  int i, ndems;
> +  int i, out, ndems;
> 
>    /* Fill the demangling_style_names[] array, and set the default
>       demangling style chosen at compilation time.  */
> -  for (ndems = 0;
> -       libiberty_demanglers[ndems].demangling_style != 
> unknown_demangling;
> -       ndems++)
> -    ;
> +  for (i = ndems = 0;
> +       libiberty_demanglers[i].demangling_style != unknown_demangling;
> +       i++)
> +    {
> +      if (libiberty_demanglers[i].demangling_style != gnat_demangling
> +	  && libiberty_demanglers[i].demangling_style != dlang_demangling
> +	  && libiberty_demanglers[i].demangling_style != rust_demangling)
> +	++ndems;
> +    }
> 
>    demangling_style_names = XCNEWVEC (const char *, ndems + 1);
> -  for (i = 0;
> +  for (i = out = 0;
>         libiberty_demanglers[i].demangling_style != unknown_demangling;
>         i++)
>      {
> -      demangling_style_names[i]
> -	= xstrdup (libiberty_demanglers[i].demangling_style_name);
> -
> -      if (current_demangling_style_string == NULL
> -	  && strcmp (DEFAULT_DEMANGLING_STYLE, demangling_style_names[i]) == 
> 0)
> -	current_demangling_style_string = demangling_style_names[i];
> +      if (libiberty_demanglers[i].demangling_style != gnat_demangling
> +	  && libiberty_demanglers[i].demangling_style != dlang_demangling
> +	  && libiberty_demanglers[i].demangling_style != rust_demangling)
> +	{

If this condition is replicated in the two loops, it should be factored 
out in a function (although check comment below).

> +	  demangling_style_names[out]
> +	    = xstrdup (libiberty_demanglers[out].demangling_style_name);

Shouldn't this be libiberty_demangers[i].demangling_style_name?

For looping, I'd prefer if you iterated with a pointer:

   for (const demangler_engine *dem_iter = libiberty_demanglers;
        dem_iter->demangling_style != unknown_demangling;
        dem_iter++)

> +
> +	  if (current_demangling_style_string == NULL
> +	      && strcmp (DEFAULT_DEMANGLING_STYLE,
> +			 demangling_style_names[out]) == 0)
> +	    current_demangling_style_string = demangling_style_names[out];
> +	  ++out;
> +	}

This seems fragile to me.  set_demangling_command relies on the fact 
that the names are at the same indices in demangling_style_names as the 
corresponding demangler in libiberty_demanglers.  With your patch it 
only works because dlang, rust and gnat are the last three items of the 
libiberty_demanglers array, so all the indices happen to match.  If you 
were to omit lucid, for example, the indices would be off.

I think that could be fixed by making set_demangling_command not use 
demangling_style_names.  Btw, do you have any idea why it does

   current_demangling_style_string = demangling_style_names[i];

?  At that point we have just verified that the demangling style name 
chosen by the user matches the name of a demangler (the strcmp), why do 
we need to set it to a string from the demangling_style_names array?  
Can't we just leave it as is?  I think we could just delete that line.  
Then, demangling_style_names would only be used for passing to 
add_setshow_enum_cmd, so it could be a static local variable in 
_initialize_demangler.  And making it an std::vector would probably 
allow you to get rid of the first loop and simplify the second one.  
Something like that:

   static std::vector<const char *> demangling_style_names;

   for (const demangler_engine *dem_iter = libiberty_demanglers;
        dem_iter->demangling_style != unknown_demangling;
        dem_iter++)
     {
       if (want_demangler (dem_iter->demangling_style))
	{
	  const char *dem_name = xstrdup (dem_iter->demangling_style_name);

	  demangling_style_names.push_back (dem_name);

	  if (current_demangling_style_string == NULL
	      && strcmp (DEFAULT_DEMANGLING_STYLE, dem_name))
	    current_demangling_style_string = dem_name;
	}
     }



Thanks,

Simon
  
Tom Tromey April 22, 2017, 6:17 a.m. UTC | #2
>>>>> "Simon" == Simon Marchi <simon.marchi@polymtl.ca> writes:

Simon> It looks like you got the wrong PR number, I think it should be 20367.

Oops.  Thanks for catching that.

Simon> Here for example, could you provide an example of when things go wrong
Simon> (a Rust symbol wrongfully demangled as a C++ symbol)?

Sure, there's one in the patch:

_ZN34_$LT$bc..X$u20$as$u20$bc..What$GT$4what17hec04869420f7eb7fE

The C++ demangler thinks it understands this and transforms it to

_$LT$bc..X$u20$as$u20$bc..What$GT$::what::hec04869420f7eb7f

However, it's actually the Rust symbol:

<bc::X as bc::What>::what

The issue here is that Rust chose a C++-like mangling.  This was
probably a mistake.  Maybe something can be done about it, maybe not --
but meanwhile I think it's nice if gdb can try to cope.

>> * ... and, in light of this change, "set demangle-style" seems a bit
>> weird because it allows the setting of styles to things obviously
>> not related to C++ at all, hence a change in demangle.c.

Simon> If other languages have mangling too, why shouldn't we be able to set
Simon> the mangling to that style?  For example, why shouldn't we be able to
Simon> do "set demangle-style rust"?

In my view, "set demangle-style" is not very useful.

If you do set it, it affects future symbols only.  It doesn't affect the
ones already read.  And, if you set it to something nonsensical, like
"java", then other parts of the C++ support will break, because
cp-name-parser only understands the C++ form.

Also it mixes the mangled form (like "Lucid") with the output form (like
"Java"), which seems odd.

>> +char *
>> +gdb_demangle_cxx (const char *mangled, int options)
>> +{
>> +  int style = (DMGL_GNU | DMGL_LUCID | DMGL_ARM
>> +	       | DMGL_HP | DMGL_EDG | DMGL_GNU_V3);
>> +
>> +  if ((current_demangling_style & DMGL_AUTO) == 0)
>> +    style &= current_demangling_style;

Simon> This deserves a comment, what does it accomplish?  Restrict the style
Simon> to a restricted set of styles?

Yes, it tries to obey "set demangle-style".  However, if demangle-style
is "auto", then there's no need to do anything else.

Simon> Shouldn't this be libiberty_demangers[i].demangling_style_name?

Yeah.

I'll make the other changes.

Tom
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f033ced..a96507a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,16 @@ 
+2017-04-16  Tom Tromey  <tom@tromey.com>
+
+	PR rust/20268:
+	* demangle.c (_initialize_demangler): Filter out non-C++ styles.
+	* symtab.c (symbol_natural_name, symbol_demangled_name): Demangle
+	for language_rust.
+	* cp-support.h (gdb_demangle_cxx): Declare.
+	* cp-support.c (gdb_demangle_cxx): New function.
+	(gdb_sniff_from_mangled_name): Use it.
+	* c-lang.c (cplus_language_defn): Reference gdb_demangle_cxx.
+	* rust-lang.c (rust_sniff_from_mangled_name): Call rust_demangle.
+	(rust_language_defn): Reference rust_demangle.
+
 2017-04-17  Joel Brobecker  <brobecker@adacore.com>
 
 	* NEWS: Create a new section for the next release branch.
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 19a8608..874916e 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -995,7 +995,7 @@  const struct language_defn cplus_language_defn =
   "this",                       /* name_of_this */
   cp_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   cp_lookup_transparent_type,   /* lookup_transparent_type */
-  gdb_demangle,			/* Language specific symbol demangler */
+  gdb_demangle_cxx,	        /* Language specific symbol demangler */
   gdb_sniff_from_mangled_name,
   cp_class_name_from_physname,  /* Language specific
 				   class_name_from_physname */
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 5704466..1a86532 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1588,10 +1588,31 @@  gdb_demangle (const char *name, int options)
 
 /* See cp-support.h.  */
 
+char *
+gdb_demangle_cxx (const char *mangled, int options)
+{
+  int style = (DMGL_GNU | DMGL_LUCID | DMGL_ARM
+	       | DMGL_HP | DMGL_EDG | DMGL_GNU_V3);
+
+  if ((current_demangling_style & DMGL_AUTO) == 0)
+    style &= current_demangling_style;
+
+  char *ret = gdb_demangle (mangled, (options | DMGL_PARAMS | DMGL_ANSI
+				      | style));
+  if (rust_is_mangled (ret))
+    {
+      xfree (ret);
+      ret = NULL;
+    }
+  return ret;
+}
+
+/* See cp-support.h.  */
+
 int
 gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
 {
-  *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+  *demangled = gdb_demangle_cxx (mangled, 0);
   return *demangled != NULL;
 }
 
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 9054bf6..aaca67e 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -157,7 +157,13 @@  extern struct cmd_list_element *maint_cplus_cmd_list;
 
 char *gdb_demangle (const char *name, int options);
 
-/* Like gdb_demangle, but suitable for use as la_sniff_from_mangled_name.  */
+/* A wrapper for gdb_demangle that will only successfully demangle C++
+   names.  */
+
+char *gdb_demangle_cxx (const char *mangled, int options);
+
+/* Like gdb_demangle_cxx, but suitable for use as
+   la_sniff_from_mangled_name.  */
 
 int gdb_sniff_from_mangled_name (const char *mangled, char **demangled);
 
diff --git a/gdb/demangle.c b/gdb/demangle.c
index 2d79c1d..d9ed896 100644
--- a/gdb/demangle.c
+++ b/gdb/demangle.c
@@ -232,25 +232,37 @@  extern initialize_file_ftype _initialize_demangler; /* -Wmissing-prototypes */
 void
 _initialize_demangler (void)
 {
-  int i, ndems;
+  int i, out, ndems;
 
   /* Fill the demangling_style_names[] array, and set the default
      demangling style chosen at compilation time.  */
-  for (ndems = 0;
-       libiberty_demanglers[ndems].demangling_style != unknown_demangling; 
-       ndems++)
-    ;
+  for (i = ndems = 0;
+       libiberty_demanglers[i].demangling_style != unknown_demangling;
+       i++)
+    {
+      if (libiberty_demanglers[i].demangling_style != gnat_demangling
+	  && libiberty_demanglers[i].demangling_style != dlang_demangling
+	  && libiberty_demanglers[i].demangling_style != rust_demangling)
+	++ndems;
+    }
   demangling_style_names = XCNEWVEC (const char *, ndems + 1);
-  for (i = 0;
+  for (i = out = 0;
        libiberty_demanglers[i].demangling_style != unknown_demangling; 
        i++)
     {
-      demangling_style_names[i]
-	= xstrdup (libiberty_demanglers[i].demangling_style_name);
-
-      if (current_demangling_style_string == NULL
-	  && strcmp (DEFAULT_DEMANGLING_STYLE, demangling_style_names[i]) == 0)
-	current_demangling_style_string = demangling_style_names[i];
+      if (libiberty_demanglers[i].demangling_style != gnat_demangling
+	  && libiberty_demanglers[i].demangling_style != dlang_demangling
+	  && libiberty_demanglers[i].demangling_style != rust_demangling)
+	{
+	  demangling_style_names[out]
+	    = xstrdup (libiberty_demanglers[out].demangling_style_name);
+
+	  if (current_demangling_style_string == NULL
+	      && strcmp (DEFAULT_DEMANGLING_STYLE,
+			 demangling_style_names[out]) == 0)
+	    current_demangling_style_string = demangling_style_names[out];
+	  ++out;
+	}
     }
 
   add_setshow_boolean_cmd ("demangle", class_support, &demangle, _("\
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index fe8a58c..13c88d9 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -2116,7 +2116,7 @@  rust_lookup_symbol_nonlocal (const struct language_defn *langdef,
 static int
 rust_sniff_from_mangled_name (const char *mangled, char **demangled)
 {
-  *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+  *demangled = rust_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
   return *demangled != NULL;
 }
 
@@ -2163,7 +2163,7 @@  static const struct language_defn rust_language_defn =
   NULL,				/* name_of_this */
   rust_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
-  gdb_demangle,			/* Language specific symbol demangler */
+  rust_demangle,		/* Language specific symbol demangler */
   rust_sniff_from_mangled_name,
   NULL,				/* Language specific
 				   class_name_from_physname */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 20ef76d..4cfc85d 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -893,6 +893,7 @@  symbol_natural_name (const struct general_symbol_info *gsymbol)
     case language_go:
     case language_objc:
     case language_fortran:
+    case language_rust:
       if (symbol_get_demangled_name (gsymbol) != NULL)
 	return symbol_get_demangled_name (gsymbol);
       break;
@@ -919,6 +920,7 @@  symbol_demangled_name (const struct general_symbol_info *gsymbol)
     case language_go:
     case language_objc:
     case language_fortran:
+    case language_rust:
       dem_name = symbol_get_demangled_name (gsymbol);
       break;
     case language_ada:
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 42d6a8d..d60b719 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@ 
+2017-04-14  Tom Tromey  <tom@tromey.com>
+
+	PR rust/20268:
+	* gdb.rust/rdemangle.exp: New file.
+	* gdb.rust/rdemangle.rs: New file.
+
 2017-04-12  Pedro Alves  <palves@redhat.com>
 
 	PR gdb/21323
diff --git a/gdb/testsuite/gdb.rust/rdemangle.exp b/gdb/testsuite/gdb.rust/rdemangle.exp
new file mode 100644
index 0000000..7bfbf71
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/rdemangle.exp
@@ -0,0 +1,39 @@ 
+# Copyright (C) 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test Rust-specific demangling.
+
+load_lib rust-support.exp
+if {[skip_rust_tests]} {
+    continue
+}
+
+standard_testfile .rs
+# The rust compiler emits some funny debuginfo for trait impls; and if
+# gdb sees debuginfo, "info func" will prefer the debuginfo symbols to
+# the minsyms, printing the wrong thing.  So, don't enable debugging.
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {rust}]} {
+    return -1
+}
+
+gdb_test "info func what" ".*$hex *<rdemangle::X as rdemangle::What>::what" \
+    "rust demangle minsym"
+
+set symbol "_ZN34_\$LT\$bc..X\$u20\$as\$u20\$bc..What\$GT\$4what17hec04869420f7eb7fE"
+
+gdb_test "demangle -l rust -- $symbol" "<bc::X as bc::What>::what" \
+    "demangle rust symbol"
+gdb_test "demangle -l c++ -- $symbol" "Can't demangle \"\[^\"\]*\"" \
+    "do not demangle rust symbol as c++"
diff --git a/gdb/testsuite/gdb.rust/rdemangle.rs b/gdb/testsuite/gdb.rust/rdemangle.rs
new file mode 100644
index 0000000..69f937f
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/rdemangle.rs
@@ -0,0 +1,43 @@ 
+// Copyright (C) 2017 Free Software Foundation, Inc.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+struct X {}
+
+pub trait What {
+    fn what(&self);
+}
+
+impl X {
+    fn what(&self) {
+        ()
+    }
+}
+
+impl What for X {
+    fn what(&self) {
+        println!("{}", 32);
+    }
+}
+
+fn main() {
+    let x = X{};
+    x.what();
+    <X as What>::what(&x);
+    ()
+}