Introduce #[diagnostic::on_move] on Arc

This annotates the `Arc` type with the diagnostic attribute
`#[diagnostic::on_move]`. Now when a moved `Arc` is borrowed,
a suggestion to clone it is made, with a label explaining why.
This commit is contained in:
Romain Perier
2026-04-01 09:22:42 +02:00
parent 12ab1cf1fd
commit 12f8364d4d
9 changed files with 21 additions and 10 deletions
+1
View File
@@ -111,6 +111,7 @@
#![feature(core_intrinsics)]
#![feature(deprecated_suggestion)]
#![feature(deref_pure_trait)]
#![feature(diagnostic_on_move)]
#![feature(dispatch_from_dyn)]
#![feature(ergonomic_clones)]
#![feature(error_generic_member_access)]
+5
View File
@@ -261,6 +261,11 @@ macro_rules! acquire {
#[rustc_diagnostic_item = "Arc"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_insignificant_dtor]
#[diagnostic::on_move(
message = "the type `{Self}` does not implement `Copy`",
label = "this move could be avoided by cloning the original `{Self}`, which is inexpensive",
note = "consider using `Arc::clone`"
)]
pub struct Arc<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
@@ -19,7 +19,7 @@ fn execute<F>(&self, f: F)
}
fn main() {
let results = Arc::new(Mutex::new(Vec::new())); //~ NOTE move occurs because
let results = Arc::new(Mutex::new(Vec::new())); //~ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive
let pool = ThreadPool {
workers: vec![],
queue: Arc::new(()),
@@ -29,6 +29,7 @@ fn main() {
// let results = Arc::clone(&results); // Forgot this.
pool.execute(move || { //~ ERROR E0382
//~^ NOTE value moved into closure here, in previous iteration of loop
//~| NOTE consider using `Arc::clone`
//~| HELP consider cloning the value before moving it into the closure
let mut r = results.lock().unwrap(); //~ NOTE use occurs due to use in closure
r.push(i);
@@ -1,8 +1,8 @@
error[E0382]: use of moved value: `results`
error[E0382]: the type `Arc` does not implement `Copy`
--> $DIR/arc-consumed-in-looped-closure.rs:30:22
|
LL | let results = Arc::new(Mutex::new(Vec::new()));
| ------- move occurs because `results` has type `Arc<std::sync::Mutex<Vec<i32>>>`, which does not implement the `Copy` trait
| ------- this move could be avoided by cloning the original `Arc`, which is inexpensive
...
LL | for i in 0..20 {
| -------------- inside of this loop
@@ -13,12 +13,14 @@ LL | pool.execute(move || {
LL | let mut r = results.lock().unwrap();
| ------- use occurs due to use in closure
|
= note: consider using `Arc::clone`
help: consider cloning the value before moving it into the closure
|
LL ~ let value = results.clone();
LL ~ pool.execute(move || {
LL |
LL |
LL |
LL ~ let mut r = value.lock().unwrap();
|
+1 -1
View File
@@ -9,7 +9,7 @@ fn main() {
assert_eq!((*arc_v)[3], 4);
});
assert_eq!((*arc_v)[2], 3); //~ ERROR borrow of moved value: `arc_v`
assert_eq!((*arc_v)[2], 3); //~ ERROR the type `Arc` does not implement `Copy`
println!("{:?}", *arc_v);
}
+3 -2
View File
@@ -1,8 +1,8 @@
error[E0382]: borrow of moved value: `arc_v`
error[E0382]: the type `Arc` does not implement `Copy`
--> $DIR/no-capture-arc.rs:12:18
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- this move could be avoided by cloning the original `Arc`, which is inexpensive
LL |
LL | thread::spawn(move|| {
| ------ value moved into closure here
@@ -12,6 +12,7 @@ LL | assert_eq!((*arc_v)[3], 4);
LL | assert_eq!((*arc_v)[2], 3);
| ^^^^^ value borrowed here after move
|
= note: consider using `Arc::clone`
= note: borrow occurs due to deref coercion to `Vec<i32>`
help: consider cloning the value before moving it into the closure
|
+1 -1
View File
@@ -11,7 +11,7 @@ fn main() {
assert_eq!((*value)[3], 4);
});
assert_eq!((*arc_v)[2], 3); //~ ERROR borrow of moved value: `arc_v`
assert_eq!((*arc_v)[2], 3); //~ ERROR the type `Arc` does not implement `Copy`
println!("{:?}", *arc_v);
}
+1 -1
View File
@@ -10,7 +10,7 @@ fn main() {
assert_eq!((*arc_v)[3], 4);
});
assert_eq!((*arc_v)[2], 3); //~ ERROR borrow of moved value: `arc_v`
assert_eq!((*arc_v)[2], 3); //~ ERROR the type `Arc` does not implement `Copy`
println!("{:?}", *arc_v);
}
+3 -2
View File
@@ -1,8 +1,8 @@
error[E0382]: borrow of moved value: `arc_v`
error[E0382]: the type `Arc` does not implement `Copy`
--> $DIR/no-reuse-move-arc.rs:13:18
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- this move could be avoided by cloning the original `Arc`, which is inexpensive
LL |
LL | thread::spawn(move|| {
| ------ value moved into closure here
@@ -12,6 +12,7 @@ LL | assert_eq!((*arc_v)[3], 4);
LL | assert_eq!((*arc_v)[2], 3);
| ^^^^^ value borrowed here after move
|
= note: consider using `Arc::clone`
= note: borrow occurs due to deref coercion to `Vec<i32>`
help: consider cloning the value before moving it into the closure
|