diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 980bd3f..7fa861c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,27 @@
+2017-05-17  Tom Tromey  <tom@tromey.com>
+
+	PR rust/21484:
+	* rust-lang.c (exp_descriptor_rust): New function.
+	(rust_language_defn): Use it.
+	* p-lang.c (pascal_language_defn): Update.
+	* opencl-lang.c (opencl_language_defn): Update.
+	* objc-lang.c (objc_language_defn): Update.
+	* m2-lang.c (m2_language_defn): Update.
+	* language.h (struct language_defn)
+	<la_watch_location_expression>: New member.
+	* language.c (unknown_language_defn, auto_language_defn)
+	(local_language_defn): Update.
+	* go-lang.c (go_language_defn): Update.
+	* f-lang.c (f_language_defn): Update.
+	* d-lang.c (d_language_defn): Update.
+	* c-lang.h (c_watch_location_expression): Declare.
+	* c-lang.c (c_watch_location_expression): New function.
+	(c_language_defn, cplus_language_defn, asm_language_defn)
+	(minimal_language_defn): Use it.
+	* breakpoint.c (watch_command_1): Call
+	la_watch_location_expression.
+	* ada-lang.c (ada_language_defn): Update.
+
 2017-05-15  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
 	* procfs.c (procfs_create_inferior): Change prototype to match
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 58c8a2e..25c49c5 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -14047,6 +14047,7 @@ const struct language_defn ada_language_defn = {
   ada_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   ada_get_symbol_name_cmp,	/* la_get_symbol_name_cmp */
   ada_iterate_over_symbols,
   &ada_varobj_ops,
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 9d6a2f4..150b08c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11256,18 +11256,11 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
       struct type *t = value_type (val);
       CORE_ADDR addr = value_as_address (val);
 
-      t = check_typedef (TYPE_TARGET_TYPE (check_typedef (t)));
-
-      std::string name = type_to_string (t);
-
-      w->exp_string_reparse = xstrprintf ("* (%s *) %s", name.c_str (),
-					  core_addr_to_string (addr));
+      w->exp_string_reparse
+	= current_language->la_watch_location_expression (t, addr).release ();
 
       w->exp_string = xstrprintf ("-location %.*s",
 				  (int) (exp_end - exp_start), exp_start);
-
-      /* The above expression is in C.  */
-      b->language = language_c;
     }
   else
     w->exp_string = savestring (exp_start, exp_end - exp_start);
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 19a8608..a6d533d 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -712,7 +712,17 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
     }
   return evaluate_subexp_standard (expect_type, exp, pos, noside);
 }
+
+/* la_watch_location_expression for C.  */
 
+gdb::unique_xmalloc_ptr<char>
+c_watch_location_expression (struct type *type, CORE_ADDR addr)
+{
+  type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+  std::string name = type_to_string (type);
+  return gdb::unique_xmalloc_ptr<char>
+    (xstrprintf ("* (%s *) %s", name.c_str (), core_addr_to_string (addr)));
+}
 
 
 /* Table mapping opcodes into strings for printing operators
@@ -865,6 +875,7 @@ const struct language_defn c_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &c_varobj_ops,
@@ -1008,6 +1019,7 @@ const struct language_defn cplus_language_defn =
   default_print_array_index,
   cp_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &cplus_varobj_ops,
@@ -1060,6 +1072,7 @@ const struct language_defn asm_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -1112,6 +1125,7 @@ const struct language_defn minimal_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index 9746238..5ce6486 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -112,6 +112,9 @@ extern void c_emit_char (int c, struct type *type,
 
 extern const struct op_print c_op_print_tab[];
 
+extern gdb::unique_xmalloc_ptr<char> c_watch_location_expression
+     (struct type *type, CORE_ADDR addr);
+
 /* These are in c-typeprint.c: */
 
 extern void c_type_print_base (struct type *, struct ui_file *,
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 3ffdbdf..434b2e6 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -244,6 +244,7 @@ static const struct language_defn d_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 3c30d75..a9663d4 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -287,6 +287,7 @@ const struct language_defn f_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 88ddfb6..3b80cec 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -605,6 +605,7 @@ static const struct language_defn go_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/language.c b/gdb/language.c
index ee0101d..e9d9803 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -43,6 +43,7 @@
 #include "symfile.h"
 #include "cp-support.h"
 #include "frame.h"
+#include "c-lang.h"
 
 extern void _initialize_language (void);
 
@@ -859,6 +860,7 @@ const struct language_defn unknown_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -908,6 +910,7 @@ const struct language_defn auto_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -955,6 +958,7 @@ const struct language_defn local_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/language.h b/gdb/language.h
index 58bcbe8..cc0df8c 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -358,6 +358,12 @@ struct language_defn
     void (*la_get_string) (struct value *value, gdb_byte **buffer, int *length,
 			   struct type **chartype, const char **charset);
 
+    /* Return an expression that can be used for a location
+       watchpoint.  TYPE is a pointer type that points to the memory
+       to watch, and ADDR is the address of the watched memory.  */
+    gdb::unique_xmalloc_ptr<char> (*la_watch_location_expression)
+         (struct type *type, CORE_ADDR addr);
+
     /* Return a pointer to the function that should be used to match
        a symbol name against LOOKUP_NAME. This is mostly for languages
        such as Ada where the matching algorithm depends on LOOKUP_NAME.
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 03b955c..35840bf 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -393,6 +393,7 @@ const struct language_defn m2_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index e102b80..934d9c6 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -402,6 +402,7 @@ const struct language_defn objc_language_defn = {
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 6e4c185..df57b61 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -1082,6 +1082,7 @@ const struct language_defn opencl_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 1b069ef..c4fe2f6 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -30,6 +30,7 @@
 #include "valprint.h"
 #include "value.h"
 #include <ctype.h>
+#include "c-lang.h"
 
 extern void _initialize_pascal_language (void);
 
@@ -455,6 +456,7 @@ const struct language_defn pascal_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 898edda..dce184c 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -2122,6 +2122,20 @@ rust_sniff_from_mangled_name (const char *mangled, char **demangled)
 
 
 
+/* la_watch_location_expression for Rust.  */
+
+static gdb::unique_xmalloc_ptr<char>
+rust_watch_location_expression (struct type *type, CORE_ADDR addr)
+{
+  type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+  std::string name = type_to_string (type);
+  return gdb::unique_xmalloc_ptr<char>
+    (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
+		 name.c_str ()));
+}
+
+
+
 static const struct exp_descriptor exp_descriptor_rust = 
 {
   rust_print_subexp,
@@ -2176,6 +2190,7 @@ static const struct language_defn rust_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  rust_watch_location_expression,
   NULL,				/* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index b672df3..aad2778 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2017-05-17  Tom Tromey  <tom@tromey.com>
+
+	PR rust/21484:
+	* gdb.rust/watch.exp: New file.
+	* gdb.rust/watch.rs: New file.
+
 2017-05-04  Pedro Alves  <palves@redhat.com>
 
 	* gdb.python/py-record-btrace-threads.exp (check_insn_for_thread):
diff --git a/gdb/testsuite/gdb.rust/watch.exp b/gdb/testsuite/gdb.rust/watch.exp
new file mode 100644
index 0000000..0a3c055
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/watch.exp
@@ -0,0 +1,35 @@
+# 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 watch -location with Rust.
+
+load_lib rust-support.exp
+if {[skip_rust_tests]} {
+    continue
+}
+
+standard_testfile .rs
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug rust}]} {
+    return -1
+}
+
+set line [gdb_get_line_number "set breakpoint here"]
+if {![runto ${srcfile}:$line]} {
+    untested "could not run to breakpoint"
+    return -1
+}
+
+# Just setting a watchpoint was enough to trigger the bug.
+gdb_test "watch -location y" ".*watchpoint .* -location .*"
diff --git a/gdb/testsuite/gdb.rust/watch.rs b/gdb/testsuite/gdb.rust/watch.rs
new file mode 100644
index 0000000..4146ecb
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/watch.rs
@@ -0,0 +1,24 @@
+// 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)]
+
+fn main() {
+    let mut y = 7;
+    y = y + 1;                  // set breakpoint here
+    y = y + 1;
+}
