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);
+    ()
+}
