From 70cf3f4fda39193c8d78979144b7aaeafae3e97d Mon Sep 17 00:00:00 2001
From: mejrs <59372212+mejrs@users.noreply.github.com>
Date: Tue, 21 Apr 2026 23:42:33 +0200
Subject: [PATCH 1/2] Put `#[diagnostic::on_move]` on `File`

---
 library/std/src/fs.rs                         |  1 +
 library/std/src/lib.rs                        |  1 +
 .../diagnostic_namespace/on_move/std_impls.rs | 25 ++++++++++
 .../on_move/std_impls.stderr                  | 49 +++++++++++++++++++
 4 files changed, 76 insertions(+)
 create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.rs
 create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.stderr

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c75f005f18021..5192343ea4300 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -132,6 +132,7 @@ use crate::{error, fmt};
 /// [`read`]: File::read
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "File")]
+#[diagnostic::on_move(note = "you can use `File::try_clone` to duplicate a `File` instance")]
 pub struct File {
     inner: fs_imp::File,
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index faac8d9e51fd2..976577156c5bd 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -278,6 +278,7 @@
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
+#![feature(diagnostic_on_move)]
 #![feature(doc_cfg)]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.rs b/tests/ui/diagnostic_namespace/on_move/std_impls.rs
new file mode 100644
index 0000000000000..ea63d731a3434
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/std_impls.rs
@@ -0,0 +1,25 @@
+//@ dont-require-annotations: NOTE
+
+use std::fs::File;
+use std::sync::Arc;
+use std::rc::Rc;
+
+fn main(){
+    let file = File::open("foo.txt").unwrap();
+    (file, file);
+    //~^ ERROR use of moved value: `file`
+    //~| NOTE you can use `File::try_clone` to duplicate a `File` instance
+
+    let arc = Arc::new(42);
+    //~^ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive
+    (arc, arc);
+    //~^ ERROR the type `Arc` does not implement `Copy`
+    //~| NOTE consider using `Arc::clone`
+
+
+    let rc = Rc::new(12);
+    //~^ NOTE this move could be avoided by cloning the original `Rc`, which is inexpensive
+    (rc, rc);
+    //~^ ERROR the type `Rc` does not implement `Copy`
+    //~| NOTE consider using `Rc::clone`
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.stderr b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr
new file mode 100644
index 0000000000000..ba8869d9c73fb
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr
@@ -0,0 +1,49 @@
+error[E0382]: use of moved value: `file`
+  --> $DIR/std_impls.rs:9:12
+   |
+LL |     let file = File::open("foo.txt").unwrap();
+   |         ---- move occurs because `file` has type `File`, which does not implement the `Copy` trait
+LL |     (file, file);
+   |      ----  ^^^^ value used here after move
+   |      |
+   |      value moved here
+   |
+   = note: you can use `File::try_clone` to duplicate a `File` instance
+
+error[E0382]: the type `Arc` does not implement `Copy`
+  --> $DIR/std_impls.rs:15:11
+   |
+LL |     let arc = Arc::new(42);
+   |         --- this move could be avoided by cloning the original `Arc`, which is inexpensive
+LL |
+LL |     (arc, arc);
+   |      ---  ^^^ value used here after move
+   |      |
+   |      value moved here
+   |
+   = note: consider using `Arc::clone`
+help: clone the value to increment its reference count
+   |
+LL |     (arc.clone(), arc);
+   |         ++++++++
+
+error[E0382]: the type `Rc` does not implement `Copy`
+  --> $DIR/std_impls.rs:22:10
+   |
+LL |     let rc = Rc::new(12);
+   |         -- this move could be avoided by cloning the original `Rc`, which is inexpensive
+LL |
+LL |     (rc, rc);
+   |      --  ^^ value used here after move
+   |      |
+   |      value moved here
+   |
+   = note: consider using `Rc::clone`
+help: clone the value to increment its reference count
+   |
+LL |     (rc.clone(), rc);
+   |        ++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.

From ce880a47fd5b544e7b23da2066c3ff35796a4074 Mon Sep 17 00:00:00 2001
From: mejrs <59372212+mejrs@users.noreply.github.com>
Date: Thu, 23 Apr 2026 13:40:45 +0200
Subject: [PATCH 2/2] Document `#[diagnostic::on_move]` in the unstable book

---
 .../language-features/diagnostic-on-move.md   | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 src/doc/unstable-book/src/language-features/diagnostic-on-move.md

diff --git a/src/doc/unstable-book/src/language-features/diagnostic-on-move.md b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md
new file mode 100644
index 0000000000000..ba35b07361416
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md
@@ -0,0 +1,92 @@
+# `diagnostic_on_move`
+
+The tracking issue for this feature is: [#154181]
+
+------------------------
+
+The `diagnostic_on_move` feature allows use of the `#[diagnostic::on_move]` attribute. It should be
+placed on struct, enum and union declarations, though it is not an error to be located in other
+positions. This attribute is a hint to the compiler to supplement the error message when the
+annotated type is involved in a borrowcheck error.
+
+For example, [`File`] is annotated as such:
+```rust
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(note = "you can use `File::try_clone` \
+                             to duplicate a `File` instance")]
+pub struct File {
+    // ...
+}
+```
+
+When you try to use a `File` after it's already been moved, it will helpfully tell you about `try_clone`.
+
+The message and label can also be customized:
+
+```rust
+#![feature(diagnostic_on_move)]
+
+use std::marker::PhantomData;
+
+#[diagnostic::on_move(
+    message = "`{Self}` cannot be used multiple times",
+    label = "this token may only be used once",
+    note = "you can create a new `Token` with `Token::conjure()`"
+)]
+pub struct Token<'brand> {
+    spooky: PhantomData<&'brand ()>,
+}
+
+impl Token<'_> {
+    pub fn conjure<'u>() -> Token<'u> {
+        Token {
+            spooky: PhantomData,
+        }
+    }
+}
+```
+The user may try to use it like this:
+```rust,compile_fail,E0382
+# #![feature(diagnostic_on_move)]
+#
+# use std::marker::PhantomData;
+#
+# #[diagnostic::on_move(
+#     message = "`{Self}` cannot be used multiple times",
+#     label = "this token may only be used once",
+#     note = "you can create a new `Token` with `Token::conjure()`"
+# )]
+# pub struct Token<'brand> {
+#     spooky: PhantomData<&'brand ()>,
+# }
+#
+# impl Token<'_> {
+#     pub fn conjure<'u>() -> Token<'u> {
+#         Token {
+#             spooky: PhantomData,
+#         }
+#     }
+# }
+# fn main() {
+let token = Token::conjure();
+let _ = (token, token);
+# }
+```
+This will result in the following error:
+```text
+error[E0382]: `Token` cannot be used multiple times
+  --> src/main.rs:24:21
+   |
+ 1 |     let token = Token::conjure();
+   |         ----- this token may only be used once
+ 2 |     let _ = (token, token);
+   |              -----  ^^^^^ value used here after move
+   |              |
+   |              value moved here
+   |
+   = note: you can create a new `Token` with `Token::conjure()`
+```
+
+[`File`]: https://doc.rust-lang.org/nightly/std/fs/struct.File.html "File in std::fs"
+[#154181]: https://github.com/rust-lang/rust/issues/154181 "Tracking Issue for #[diagnostic::on_move]"
