Skip to content

Commit dd72b1a

Browse files
committed
Suggest ref for some patterns as a fallback
1 parent 4f7c257 commit dd72b1a

34 files changed

+476
-63
lines changed

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
460460
}
461461

462462
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
463-
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
463+
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
464464
for local in binds_to {
465465
let bind_to = &self.body.local_decls[*local];
466466
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
@@ -469,7 +469,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
469469
{
470470
let Ok(pat_snippet) =
471471
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
472-
let Some(stripped) = pat_snippet.strip_prefix('&') else { continue; };
472+
let Some(stripped) = pat_snippet.strip_prefix('&') else {
473+
suggestions.push((
474+
bind_to.source_info.span.shrink_to_lo(),
475+
"consider borrowing the pattern binding".to_string(),
476+
"ref ".to_string(),
477+
));
478+
continue;
479+
};
473480
let inner_pat_snippet = stripped.trim_start();
474481
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
475482
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
@@ -488,18 +495,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
488495
);
489496
(pat_span, String::new(), "borrow")
490497
};
491-
suggestions.push((pat_span, to_remove, suggestion.to_owned()));
498+
suggestions.push((
499+
pat_span,
500+
format!("consider removing the {to_remove}"),
501+
suggestion.to_string(),
502+
));
492503
}
493504
}
494505
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
495506
suggestions.dedup_by_key(|&mut (span, _, _)| span);
496-
for (span, to_remove, suggestion) in suggestions {
497-
err.span_suggestion_verbose(
498-
span,
499-
&format!("consider removing the {to_remove}"),
500-
suggestion,
501-
Applicability::MachineApplicable,
502-
);
507+
for (span, msg, suggestion) in suggestions {
508+
err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
503509
}
504510
}
505511

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
enum Foo {
4+
Foo1(Box<u32>, Box<u32>),
5+
Foo2(Box<u32>),
6+
Foo3,
7+
}
8+
9+
10+
11+
fn blah() {
12+
let f = &Foo::Foo1(Box::new(1), Box::new(2));
13+
match &*f { //~ ERROR cannot move out of
14+
Foo::Foo1(num1,
15+
num2) => (),
16+
Foo::Foo2(num) => (),
17+
Foo::Foo3 => ()
18+
}
19+
}
20+
21+
struct S {
22+
f: String,
23+
g: String
24+
}
25+
impl Drop for S {
26+
fn drop(&mut self) { println!("{}", self.f); }
27+
}
28+
29+
fn move_in_match() {
30+
match (S {f: "foo".to_string(), g: "bar".to_string()}) {
31+
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
32+
S {
33+
f: ref _s,
34+
g: ref _t
35+
} => {}
36+
}
37+
}
38+
39+
// from issue-8064
40+
struct A {
41+
a: Box<isize>,
42+
}
43+
44+
fn free<T>(_: T) {}
45+
46+
fn blah2() {
47+
let a = &A { a: Box::new(1) };
48+
match &a.a { //~ ERROR cannot move out of
49+
n => {
50+
free(n)
51+
}
52+
}
53+
free(a)
54+
}
55+
56+
fn main() {}

src/test/ui/borrowck/borrowck-move-error-with-note.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
#![allow(unused)]
13
enum Foo {
24
Foo1(Box<u32>, Box<u32>),
35
Foo2(Box<u32>),

src/test/ui/borrowck/borrowck-move-error-with-note.stderr

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
2-
--> $DIR/borrowck-move-error-with-note.rs:11:11
2+
--> $DIR/borrowck-move-error-with-note.rs:13:11
33
|
44
LL | match *f {
55
| ^^
@@ -17,7 +17,7 @@ LL | match &*f {
1717
| +
1818

1919
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
20-
--> $DIR/borrowck-move-error-with-note.rs:28:11
20+
--> $DIR/borrowck-move-error-with-note.rs:30:11
2121
|
2222
LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) {
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@@ -28,9 +28,17 @@ LL | g: _t
2828
| -- ...and here
2929
|
3030
= note: move occurs because these variables have types that don't implement the `Copy` trait
31+
help: consider borrowing the pattern binding
32+
|
33+
LL | f: ref _s,
34+
| +++
35+
help: consider borrowing the pattern binding
36+
|
37+
LL | g: ref _t
38+
| +++
3139

3240
error[E0507]: cannot move out of `a.a` which is behind a shared reference
33-
--> $DIR/borrowck-move-error-with-note.rs:46:11
41+
--> $DIR/borrowck-move-error-with-note.rs:48:11
3442
|
3543
LL | match a.a {
3644
| ^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
struct S {f:String}
4+
impl Drop for S {
5+
fn drop(&mut self) { println!("{}", self.f); }
6+
}
7+
8+
fn move_in_match() {
9+
match (S {f:"foo".to_string()}) {
10+
//~^ ERROR [E0509]
11+
S {f:ref _s} => {}
12+
}
13+
}
14+
15+
fn move_in_let() {
16+
let S {f:ref _s} = S {f:"foo".to_string()};
17+
//~^ ERROR [E0509]
18+
}
19+
20+
fn move_in_fn_arg(S {f:ref _s}: S) {
21+
//~^ ERROR [E0509]
22+
}
23+
24+
fn main() {}

src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
#![allow(unused)]
13
struct S {f:String}
24
impl Drop for S {
35
fn drop(&mut self) { println!("{}", self.f); }

src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
2-
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:7:11
2+
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:9:11
33
|
44
LL | match (S {f:"foo".to_string()}) {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@@ -9,25 +9,40 @@ LL | S {f:_s} => {}
99
| |
1010
| data moved here
1111
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
12+
|
13+
help: consider borrowing the pattern binding
14+
|
15+
LL | S {f:ref _s} => {}
16+
| +++
1217

1318
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
14-
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20
19+
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:16:20
1520
|
1621
LL | let S {f:_s} = S {f:"foo".to_string()};
1722
| -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
1823
| |
1924
| data moved here
2025
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
26+
|
27+
help: consider borrowing the pattern binding
28+
|
29+
LL | let S {f:ref _s} = S {f:"foo".to_string()};
30+
| +++
2131

2232
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
23-
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19
33+
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:20:19
2434
|
2535
LL | fn move_in_fn_arg(S {f:_s}: S) {
2636
| ^^^^^--^
2737
| | |
2838
| | data moved here
2939
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
3040
| cannot move out of here
41+
|
42+
help: consider borrowing the pattern binding
43+
|
44+
LL | fn move_in_fn_arg(S {f:ref _s}: S) {
45+
| +++
3146

3247
error: aborting due to 3 previous errors
3348

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
struct S(String);
4+
impl Drop for S {
5+
fn drop(&mut self) { }
6+
}
7+
8+
fn move_in_match() {
9+
match S("foo".to_string()) {
10+
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
11+
S(ref _s) => {}
12+
}
13+
}
14+
15+
fn move_in_let() {
16+
let S(ref _s) = S("foo".to_string());
17+
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
18+
}
19+
20+
fn move_in_fn_arg(S(ref _s): S) {
21+
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
22+
}
23+
24+
fn main() {}

src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
#![allow(unused)]
13
struct S(String);
24
impl Drop for S {
35
fn drop(&mut self) { }

src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
2-
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:7:11
2+
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:9:11
33
|
44
LL | match S("foo".to_string()) {
55
| ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@@ -9,25 +9,40 @@ LL | S(_s) => {}
99
| |
1010
| data moved here
1111
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
12+
|
13+
help: consider borrowing the pattern binding
14+
|
15+
LL | S(ref _s) => {}
16+
| +++
1217

1318
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
14-
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17
19+
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:16:17
1520
|
1621
LL | let S(_s) = S("foo".to_string());
1722
| -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
1823
| |
1924
| data moved here
2025
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
26+
|
27+
help: consider borrowing the pattern binding
28+
|
29+
LL | let S(ref _s) = S("foo".to_string());
30+
| +++
2131

2232
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
23-
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19
33+
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:20:19
2434
|
2535
LL | fn move_in_fn_arg(S(_s): S) {
2636
| ^^--^
2737
| | |
2838
| | data moved here
2939
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
3040
| cannot move out of here
41+
|
42+
help: consider borrowing the pattern binding
43+
|
44+
LL | fn move_in_fn_arg(S(ref _s): S) {
45+
| +++
3146

3247
error: aborting due to 3 previous errors
3348

src/test/ui/borrowck/issue-51301.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | .find(|(&event_type, _)| event == event_type)
66
| |
77
| data moved here
88
| move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait
9+
|
10+
help: consider borrowing the pattern binding
11+
|
12+
LL | .find(|(&ref event_type, _)| event == event_type)
13+
| +++
914

1015
error: aborting due to previous error
1116

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// run-rustfix
2+
// Regression test for #51415: match default bindings were failing to
3+
// see the "move out" implied by `&s` below.
4+
5+
fn main() {
6+
let a = vec![String::from("a")];
7+
let opt = a.iter().enumerate().find(|(_, &ref s)| {
8+
//~^ ERROR cannot move out
9+
*s == String::from("d")
10+
}).map(|(i, _)| i);
11+
println!("{:?}", opt);
12+
}

src/test/ui/borrowck/issue-51415.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
// Regression test for #51415: match default bindings were failing to
23
// see the "move out" implied by `&s` below.
34

src/test/ui/borrowck/issue-51415.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
error[E0507]: cannot move out of a shared reference
2-
--> $DIR/issue-51415.rs:6:42
2+
--> $DIR/issue-51415.rs:7:42
33
|
44
LL | let opt = a.iter().enumerate().find(|(_, &s)| {
55
| ^^^^^-^
66
| |
77
| data moved here
88
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
9+
|
10+
help: consider borrowing the pattern binding
11+
|
12+
LL | let opt = a.iter().enumerate().find(|(_, &ref s)| {
13+
| +++
914

1015
error: aborting due to previous error
1116

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-rustfix
2+
struct X {
3+
x: String,
4+
}
5+
6+
impl Drop for X {
7+
fn drop(&mut self) {
8+
println!("value: {}", self.x);
9+
}
10+
}
11+
12+
fn unwrap(x: X) -> String {
13+
let X { x: ref y } = x; //~ ERROR cannot move out of type
14+
y.to_string()
15+
}
16+
17+
fn main() {
18+
let x = X { x: "hello".to_string() };
19+
let y = unwrap(x);
20+
println!("contents: {}", y);
21+
}

src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
struct X {
23
x: String,
34
}
@@ -10,7 +11,7 @@ impl Drop for X {
1011

1112
fn unwrap(x: X) -> String {
1213
let X { x: y } = x; //~ ERROR cannot move out of type
13-
y
14+
y.to_string()
1415
}
1516

1617
fn main() {

0 commit comments

Comments
 (0)