format!("variable moved due to use{}", move_spans.describe()),
);
}
+ if let UseSpans::PatUse(span) = move_spans {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "borrow this field in the pattern to avoid moving {}",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the value".to_string())
+ ),
+ "ref ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+
if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
let sess = self.infcx.tcx.sess;
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
_ => true,
};
- if needs_note {
- let mpi = self.move_data.moves[move_out_indices[0]].path;
- let place = &self.move_data.move_paths[mpi].place;
+ let mpi = self.move_data.moves[move_out_indices[0]].path;
+ let place = &self.move_data.move_paths[mpi].place;
+ let ty = place.ty(self.body, self.infcx.tcx).ty;
+
+ if is_loop_move {
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind {
+ // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place)
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the mutable reference".to_string()),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
- let ty = place.ty(self.body, self.infcx.tcx).ty;
+ if needs_note {
let opt_name =
self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
let note_msg = match opt_name {
// Used in a closure.
(LaterUseKind::ClosureCapture, var_span)
}
- UseSpans::OtherUse(span) => {
+ UseSpans::PatUse(span) | UseSpans::OtherUse(span) => {
let block = &self.body.basic_blocks()[location.block];
let kind = if let Some(&Statement {
// The span of the first use of the captured variable inside the closure.
var_span: Span,
},
- // This access has a single span associated to it: common case.
+ /// This access is caused by a `match` or `if let` pattern.
+ PatUse(Span),
+ /// This access has a single span associated to it: common case.
OtherUse(Span),
}
impl UseSpans {
pub(super) fn args_or_use(self) -> Span {
match self {
- UseSpans::ClosureUse { args_span: span, .. } | UseSpans::OtherUse(span) => span,
+ UseSpans::ClosureUse { args_span: span, .. }
+ | UseSpans::PatUse(span)
+ | UseSpans::OtherUse(span) => span,
}
}
pub(super) fn var_or_use(self) -> Span {
match self {
- UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
+ UseSpans::ClosureUse { var_span: span, .. }
+ | UseSpans::PatUse(span)
+ | UseSpans::OtherUse(span) => span,
}
}
{
match self {
closure @ UseSpans::ClosureUse { .. } => closure,
- UseSpans::OtherUse(_) => if_other(),
+ UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
}
}
}
}
}
- OtherUse(stmt.source_info.span)
+ if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
+ PatUse(stmt.source_info.span)
+ } else {
+ OtherUse(stmt.source_info.span)
+ }
}
/// Finds the span of arguments of a closure (within `maybe_closure_span`)
| ^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+ |
+LL | if let Some(ref thing) = maybe {
+ | ^^^
error: aborting due to previous error
--- /dev/null
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(mut x) = s {
+ x = S;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let mut e = E::V { s: S };
+ let E::V { s: mut x } = e;
+ x = S;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+error[E0382]: use of moved value: `s`
+ --> $DIR/move-in-pattern-mut.rs:18:9
+ |
+LL | if let Some(mut x) = s {
+ | ----- value moved here
+...
+LL | foo(s);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+ |
+LL | if let Some(ref mut x) = s {
+ | ^^^
+
+error[E0382]: use of moved value: `e`
+ --> $DIR/move-in-pattern-mut.rs:22:9
+ |
+LL | let E::V { s: mut x } = e;
+ | ----- value moved here
+LL | x = S;
+LL | bar(e);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+ |
+LL | let E::V { s: ref mut x } = e;
+ | ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(ref x) = s {
+ let _ = x;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let e = E::V { s: S };
+ let E::V { s: ref x } = e;
+ let _ = x;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(x) = s {
+ let _ = x;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let e = E::V { s: S };
+ let E::V { s: x } = e;
+ let _ = x;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+error[E0382]: use of moved value: `s`
+ --> $DIR/move-in-pattern.rs:19:9
+ |
+LL | if let Some(x) = s {
+ | - value moved here
+...
+LL | foo(s);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+ |
+LL | if let Some(ref x) = s {
+ | ^^^
+
+error[E0382]: use of moved value: `e`
+ --> $DIR/move-in-pattern.rs:23:9
+ |
+LL | let E::V { s: x } = e;
+ | - value moved here
+LL | let _ = x;
+LL | bar(e);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+ |
+LL | let E::V { s: ref x } = e;
+ | ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+ fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+ fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+ fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value);
+ }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value); //~ ERROR use of moved value: `value`
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+ fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+ fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+ fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value);
+ }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(value); //~ ERROR use of moved value: `value`
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `value`
+ --> $DIR/mut-borrow-in-loop-2.rs:31:23
+ |
+LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ | ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
+LL | for _ in 0..3 {
+LL | Other::handle(value);
+ | ^^^^^ value moved here, in previous iteration of loop
+ |
+help: consider creating a fresh reborrow of `value` here
+ |
+LL | Other::handle(&mut *value);
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
| ^^^^ value used here after partial move
|
= note: move occurs because value has type `std::boxed::Box<List>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `node.next.0`
+ |
+LL | Some(ref right) => consume(right),
+ | ^^^
error: aborting due to previous error
| ^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+ |
+LL | if let Some(ref thing) = maybe {
+ | ^^^
error: aborting due to previous error
| value moved here
|
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+ |
+LL | Some(ref _z @ ref _y) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19
| value moved here
|
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+ |
+LL | Some(ref _z @ ref mut _y) => {}
+ | ^^^
error: aborting due to 6 previous errors
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | ^^^
error[E0382]: use of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | ^^^
error[E0382]: use of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30
| ^ value used here after partial move
|
= note: move occurs because value has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0.0`
+ |
+LL | (Some(ref y), ()) => {},
+ | ^^^
error: aborting due to 3 previous errors