Skip to content

Commit 0ca5003

Browse files
committed
Auto merge of #106095 - estebank:pin-mut-reborrow, r=compiler-errors
Suggest `Pin::as_mut` when encountering borrow error Fix #65409 for `Pin<&mut T>`.
2 parents e396186 + 8a13a7c commit 0ca5003

17 files changed

+205
-23
lines changed

Diff for: compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
194194

195195
if !seen_spans.contains(&move_span) {
196196
if !closure {
197-
self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern);
197+
self.suggest_ref_or_clone(
198+
mpi,
199+
move_span,
200+
&mut err,
201+
&mut in_pattern,
202+
move_spans,
203+
);
198204
}
199205

200206
self.explain_captures(
@@ -312,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
312318
move_span: Span,
313319
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
314320
in_pattern: &mut bool,
321+
move_spans: UseSpans<'_>,
315322
) {
316323
struct ExpressionFinder<'hir> {
317324
expr_span: Span,
@@ -440,6 +447,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
440447
) = call_expr.kind
441448
{
442449
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
450+
} else if let UseSpans::FnSelfUse {
451+
kind: CallKind::Normal { .. },
452+
..
453+
} = move_spans {
454+
// We already suggest cloning for these cases in `explain_captures`.
443455
} else {
444456
self.suggest_cloning(err, ty, move_span);
445457
}

Diff for: compiler/rustc_borrowck/src/diagnostics/mod.rs

+46-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diagnostic};
66
use rustc_hir as hir;
77
use rustc_hir::def::{CtorKind, Namespace};
88
use rustc_hir::GeneratorKind;
9-
use rustc_infer::infer::TyCtxtInferExt;
9+
use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
1010
use rustc_middle::mir::tcx::PlaceTy;
1111
use rustc_middle::mir::{
1212
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@@ -18,7 +18,10 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
1818
use rustc_span::def_id::LocalDefId;
1919
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
2020
use rustc_target::abi::VariantIdx;
21-
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
21+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
22+
use rustc_trait_selection::traits::{
23+
type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
24+
};
2225

2326
use super::borrow_set::BorrowData;
2427
use super::MirBorrowckCtxt;
@@ -1066,18 +1069,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10661069
}
10671070
CallKind::Normal { self_arg, desugaring, method_did } => {
10681071
let self_arg = self_arg.unwrap();
1072+
let tcx = self.infcx.tcx;
10691073
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
1070-
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
1071-
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
1074+
let ty = moved_place.ty(self.body, tcx).ty;
1075+
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
10721076
Some(def_id) => {
10731077
let infcx = self.infcx.tcx.infer_ctxt().build();
10741078
type_known_to_meet_bound_modulo_regions(
10751079
&infcx,
10761080
self.param_env,
1077-
infcx.tcx.mk_imm_ref(
1078-
infcx.tcx.lifetimes.re_erased,
1079-
infcx.tcx.erase_regions(ty),
1080-
),
1081+
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
10811082
def_id,
10821083
DUMMY_SP,
10831084
)
@@ -1133,8 +1134,44 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11331134
place_name, partially_str, loop_message
11341135
),
11351136
);
1137+
let infcx = tcx.infer_ctxt().build();
1138+
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
1139+
if let ty::Adt(def, substs) = ty.kind()
1140+
&& Some(def.did()) == tcx.lang_items().pin_type()
1141+
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
1142+
&& let self_ty = infcx.replace_bound_vars_with_fresh_vars(
1143+
fn_call_span,
1144+
LateBoundRegionConversionTime::FnCall,
1145+
tcx.fn_sig(method_did).input(0),
1146+
)
1147+
&& infcx.can_eq(self.param_env, ty, self_ty).is_ok()
1148+
{
1149+
err.span_suggestion_verbose(
1150+
fn_call_span.shrink_to_lo(),
1151+
"consider reborrowing the `Pin` instead of moving it",
1152+
"as_mut().".to_string(),
1153+
Applicability::MaybeIncorrect,
1154+
);
1155+
}
1156+
if let Some(clone_trait) = tcx.lang_items().clone_trait()
1157+
&& let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
1158+
&& let o = Obligation::new(
1159+
tcx,
1160+
ObligationCause::dummy(),
1161+
self.param_env,
1162+
ty::Binder::dummy(trait_ref),
1163+
)
1164+
&& infcx.predicate_must_hold_modulo_regions(&o)
1165+
{
1166+
err.span_suggestion_verbose(
1167+
fn_call_span.shrink_to_lo(),
1168+
"you can `clone` the value and consume it, but this might not be \
1169+
your desired behavior",
1170+
"clone().".to_string(),
1171+
Applicability::MaybeIncorrect,
1172+
);
1173+
}
11361174
}
1137-
let tcx = self.infcx.tcx;
11381175
// Avoid pointing to the same function in multiple different
11391176
// error messages.
11401177
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {

Diff for: src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ LL | let _x = Rc::new(vec![1, 2]).into_iter();
99
|
1010
note: `into_iter` takes ownership of the receiver `self`, which moves value
1111
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
12+
help: you can `clone` the value and consume it, but this might not be your desired behavior
13+
|
14+
LL | let _x = Rc::new(vec![1, 2]).clone().into_iter();
15+
| ++++++++
1216

1317
error: aborting due to previous error
1418

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
// Test that a by-ref `FnMut` closure gets an error when it tries to
3+
// consume a value.
4+
5+
fn call<F>(f: F) where F : Fn() {
6+
f();
7+
}
8+
9+
fn main() {
10+
let y = vec![format!("World")];
11+
call(|| {
12+
y.clone().into_iter();
13+
//~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
14+
});
15+
}

Diff for: src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
// Test that a by-ref `FnMut` closure gets an error when it tries to
23
// consume a value.
34

Diff for: src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
2-
--> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9
2+
--> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:12:9
33
|
44
LL | let y = vec![format!("World")];
55
| - captured outer variable
@@ -12,6 +12,10 @@ LL | y.into_iter();
1212
|
1313
note: `into_iter` takes ownership of the receiver `self`, which moves `y`
1414
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
15+
help: you can `clone` the value and consume it, but this might not be your desired behavior
16+
|
17+
LL | y.clone().into_iter();
18+
| ++++++++
1519

1620
error: aborting due to previous error
1721

Diff for: src/test/ui/codemap_tests/tab_3.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ LL | println!("{:?}", some_vec);
1212
note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec`
1313
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1414
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
15-
help: consider cloning the value if the performance cost is acceptable
15+
help: you can `clone` the value and consume it, but this might not be your desired behavior
1616
|
1717
LL | some_vec.clone().into_iter();
18-
| ++++++++
18+
| ++++++++
1919

2020
error: aborting due to previous error
2121

Diff for: src/test/ui/moves/move-fn-self-receiver.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ LL | val.0;
99
note: `into_iter` takes ownership of the receiver `self`, which moves `val.0`
1010
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1111
= note: move occurs because `val.0` has type `Vec<bool>`, which does not implement the `Copy` trait
12+
help: you can `clone` the value and consume it, but this might not be your desired behavior
13+
|
14+
LL | val.0.clone().into_iter().next();
15+
| ++++++++
1216

1317
error[E0382]: use of moved value: `foo`
1418
--> $DIR/move-fn-self-receiver.rs:34:5
@@ -93,10 +97,10 @@ note: `Foo::use_rc_self` takes ownership of the receiver `self`, which moves `rc
9397
|
9498
LL | fn use_rc_self(self: Rc<Self>) {}
9599
| ^^^^
96-
help: consider cloning the value if the performance cost is acceptable
100+
help: you can `clone` the value and consume it, but this might not be your desired behavior
97101
|
98102
LL | rc_foo.clone().use_rc_self();
99-
| ++++++++
103+
| ++++++++
100104

101105
error[E0382]: use of moved value: `foo_add`
102106
--> $DIR/move-fn-self-receiver.rs:59:5
@@ -136,10 +140,10 @@ LL | for _val in explicit_into_iter.into_iter() {}
136140
LL | explicit_into_iter;
137141
| ^^^^^^^^^^^^^^^^^^ value used here after move
138142
|
139-
help: consider cloning the value if the performance cost is acceptable
143+
help: you can `clone` the value and consume it, but this might not be your desired behavior
140144
|
141145
LL | for _val in explicit_into_iter.clone().into_iter() {}
142-
| ++++++++
146+
| ++++++++
143147

144148
error[E0382]: use of moved value: `container`
145149
--> $DIR/move-fn-self-receiver.rs:71:5

Diff for: src/test/ui/moves/moves-based-on-type-access-to-field.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ LL | touch(&x[0]);
1010
|
1111
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
1212
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
13-
help: consider cloning the value if the performance cost is acceptable
13+
help: you can `clone` the value and consume it, but this might not be your desired behavior
1414
|
1515
LL | consume(x.clone().into_iter().next().unwrap());
16-
| ++++++++
16+
| ++++++++
1717

1818
error: aborting due to previous error
1919

Diff for: src/test/ui/moves/moves-based-on-type-exprs.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,10 @@ LL | touch(&x);
162162
|
163163
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
164164
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
165-
help: consider cloning the value if the performance cost is acceptable
165+
help: you can `clone` the value and consume it, but this might not be your desired behavior
166166
|
167167
LL | let _y = x.clone().into_iter().next().unwrap();
168-
| ++++++++
168+
| ++++++++
169169

170170
error[E0382]: borrow of moved value: `x`
171171
--> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -179,10 +179,10 @@ LL | touch(&x);
179179
|
180180
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
181181
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
182-
help: consider cloning the value if the performance cost is acceptable
182+
help: you can `clone` the value and consume it, but this might not be your desired behavior
183183
|
184184
LL | let _y = [x.clone().into_iter().next().unwrap(); 1];
185-
| ++++++++
185+
| ++++++++
186186

187187
error: aborting due to 11 previous errors
188188

Diff for: src/test/ui/moves/pin-mut-reborrow.fixed

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
use std::pin::Pin;
3+
4+
struct Foo;
5+
6+
impl Foo {
7+
fn foo(self: Pin<&mut Self>) {}
8+
}
9+
10+
fn main() {
11+
let mut foo = Foo;
12+
let mut foo = Pin::new(&mut foo);
13+
foo.as_mut().foo();
14+
foo.foo(); //~ ERROR use of moved value
15+
}

Diff for: src/test/ui/moves/pin-mut-reborrow.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
use std::pin::Pin;
3+
4+
struct Foo;
5+
6+
impl Foo {
7+
fn foo(self: Pin<&mut Self>) {}
8+
}
9+
10+
fn main() {
11+
let mut foo = Foo;
12+
let mut foo = Pin::new(&mut foo);
13+
foo.foo();
14+
foo.foo(); //~ ERROR use of moved value
15+
}

Diff for: src/test/ui/moves/pin-mut-reborrow.stderr

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0382]: use of moved value: `foo`
2+
--> $DIR/pin-mut-reborrow.rs:14:5
3+
|
4+
LL | let mut foo = Pin::new(&mut foo);
5+
| ------- move occurs because `foo` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
6+
LL | foo.foo();
7+
| ----- `foo` moved due to this method call
8+
LL | foo.foo();
9+
| ^^^ value used here after move
10+
|
11+
note: `Foo::foo` takes ownership of the receiver `self`, which moves `foo`
12+
--> $DIR/pin-mut-reborrow.rs:7:12
13+
|
14+
LL | fn foo(self: Pin<&mut Self>) {}
15+
| ^^^^
16+
help: consider reborrowing the `Pin` instead of moving it
17+
|
18+
LL | foo.as_mut().foo();
19+
| +++++++++
20+
21+
error: aborting due to previous error
22+
23+
For more information about this error, try `rustc --explain E0382`.

Diff for: src/test/ui/moves/suggest-clone.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
3+
#[derive(Clone)]
4+
struct Foo;
5+
impl Foo {
6+
fn foo(self) {}
7+
}
8+
fn main() {
9+
let foo = &Foo;
10+
foo.clone().foo(); //~ ERROR cannot move out
11+
}

Diff for: src/test/ui/moves/suggest-clone.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
3+
#[derive(Clone)]
4+
struct Foo;
5+
impl Foo {
6+
fn foo(self) {}
7+
}
8+
fn main() {
9+
let foo = &Foo;
10+
foo.foo(); //~ ERROR cannot move out
11+
}

Diff for: src/test/ui/moves/suggest-clone.stderr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0507]: cannot move out of `*foo` which is behind a shared reference
2+
--> $DIR/suggest-clone.rs:10:5
3+
|
4+
LL | foo.foo();
5+
| ^^^^-----
6+
| | |
7+
| | `*foo` moved due to this method call
8+
| move occurs because `*foo` has type `Foo`, which does not implement the `Copy` trait
9+
|
10+
note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
11+
--> $DIR/suggest-clone.rs:6:12
12+
|
13+
LL | fn foo(self) {}
14+
| ^^^^
15+
help: you can `clone` the value and consume it, but this might not be your desired behavior
16+
|
17+
LL | foo.clone().foo();
18+
| ++++++++
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0507`.

Diff for: src/test/ui/suggestions/option-content-move.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ LL | if selection.1.unwrap().contains(selection.0) {
99
|
1010
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
1111
--> $SRC_DIR/core/src/option.rs:LL:COL
12+
help: you can `clone` the value and consume it, but this might not be your desired behavior
13+
|
14+
LL | if selection.1.clone().unwrap().contains(selection.0) {
15+
| ++++++++
1216

1317
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
1418
--> $DIR/option-content-move.rs:27:20
@@ -21,6 +25,10 @@ LL | if selection.1.unwrap().contains(selection.0) {
2125
|
2226
note: `Result::<T, E>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
2327
--> $SRC_DIR/core/src/result.rs:LL:COL
28+
help: you can `clone` the value and consume it, but this might not be your desired behavior
29+
|
30+
LL | if selection.1.clone().unwrap().contains(selection.0) {
31+
| ++++++++
2432

2533
error: aborting due to 2 previous errors
2634

0 commit comments

Comments
 (0)