From 98752776b853cad6fc99f51d91f7fdd797490a8d Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Wed, 2 Mar 2022 04:30:16 +0000 Subject: [PATCH] Tweak move error Point at method definition that causes type to be consumed. Fix #94056. --- .../src/diagnostics/conflict_errors.rs | 155 ++------------- .../rustc_borrowck/src/diagnostics/mod.rs | 179 +++++++++++++++++- .../src/diagnostics/move_errors.rs | 44 +---- ...ature-nll-overrides-migrate.edition.stderr | 6 +- ...feature-nll-overrides-migrate.zflag.stderr | 6 +- .../borrowck/borrowck-move-by-capture.stderr | 2 +- ...k-move-out-of-overloaded-auto-deref.stderr | 11 +- .../issue-27282-mutation-in-guard.stderr | 6 +- ...ove-upvar-from-non-once-ref-closure.stderr | 10 +- src/test/ui/error-codes/E0507.stderr | 11 +- ...issue-27282-move-ref-mut-into-guard.stderr | 6 +- src/test/ui/issues/issue-61108.stderr | 9 +- src/test/ui/issues/issue-64559.stderr | 9 +- src/test/ui/loops/issue-82916.stderr | 9 +- .../ui/moves/issue-46099-move-in-macro.stderr | 5 +- .../ui/moves/move-fn-self-receiver.stderr | 10 +- src/test/ui/moves/move-in-guard-2.stderr | 5 +- .../ui/nll/match-guards-always-borrow.stderr | 6 +- .../suggestions/borrow-for-loop-head.stderr | 9 +- src/test/ui/suggestions/for-i-in-vec.stderr | 31 ++- .../suggestions/option-content-move2.stderr | 2 +- 21 files changed, 289 insertions(+), 242 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 684a3ced5a070..3eef907d9ed3d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,5 +1,5 @@ use either::Either; -use rustc_const_eval::util::{CallDesugaringKind, CallKind}; +use rustc_const_eval::util::CallKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; @@ -17,7 +17,7 @@ use rustc_middle::ty::{ }; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::symbol::sym; -use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_span::{BytePos, MultiSpan, Span}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::TraitEngineExt as _; @@ -195,144 +195,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_move = true; } - if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { - let place_name = self - .describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "value".to_owned()); - match kind { - CallKind::FnCall { fn_trait_id, .. } - if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => - { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this call{}", - place_name, partially_str, loop_message - ), - ); - err.span_note( - var_span, - "this value implements `FnOnce`, which causes it to be moved when called", - ); - } - CallKind::Operator { self_arg, .. } => { - let self_arg = self_arg.unwrap(); - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to usage in operator{}", - place_name, partially_str, loop_message - ), - ); - if self.fn_self_span_reported.insert(fn_span) { - err.span_note( - // Check whether the source is accessible - if self - .infcx - .tcx - .sess - .source_map() - .span_to_snippet(self_arg.span) - .is_ok() - { - self_arg.span - } else { - fn_call_span - }, - "calling this operator moves the left-hand side", - ); - } - } - CallKind::Normal { self_arg, desugaring, is_option_or_result } => { - let self_arg = self_arg.unwrap(); - if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this implicit call to `.into_iter()`{}", - place_name, partially_str, loop_message - ), - ); - let sess = self.infcx.tcx.sess; - let ty = used_place.ty(self.body, self.infcx.tcx).ty; - // If we have a `&mut` ref, we need to reborrow. - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { - // If we are in a loop this will be suggested later. - if !is_loop_move { - err.span_suggestion_verbose( - move_span.shrink_to_lo(), - &format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else( - || "the mutable reference".to_string() - ), - ), - "&mut *".to_string(), - Applicability::MachineApplicable, - ); - } - } else if let Ok(snippet) = - sess.source_map().span_to_snippet(move_span) - { - err.span_suggestion( - move_span, - "consider borrowing to avoid moving into the for loop", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); - } - } else { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this method call{}", - place_name, partially_str, loop_message - ), - ); - } - if is_option_or_result && maybe_reinitialized_locations.is_empty() { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` to borrow the type's contents", - "as_ref().".to_string(), - Applicability::MachineApplicable, - ); - } - // Avoid pointing to the same function in multiple different - // error messages. - if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) - { - err.span_note( - self_arg.span, - &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) - ); - } - } - // Other desugarings takes &self, which cannot cause a move - _ => unreachable!(), - } - } else { - err.span_label( - move_span, - format!("value {}moved{} here{}", partially_str, move_msg, loop_message), - ); - // If the move error occurs due to a loop, don't show - // another message for the same span - if loop_message.is_empty() { - move_spans.var_span_label( - &mut err, - format!( - "variable {}moved due to use{}", - partially_str, - move_spans.describe() - ), - "moved", - ); - } - } + self.explain_captures( + &mut err, + span, + move_span, + move_spans, + *moved_place, + Some(used_place), + partially_str, + loop_message, + move_msg, + is_loop_move, + maybe_reinitialized_locations.is_empty(), + ); if let (UseSpans::PatUse(span), []) = (move_spans, &maybe_reinitialized_locations[..]) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 754856043b3b5..164ebfed0f795 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,11 +1,12 @@ //! Borrow checker diagnostics. -use rustc_const_eval::util::call_kind; -use rustc_errors::Diagnostic; +use rustc_const_eval::util::{call_kind, CallDesugaringKind}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_hir::GeneratorKind; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::{ AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, @@ -13,8 +14,9 @@ use rustc_middle::mir::{ use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; +use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -482,9 +484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { BorrowedContentSource::DerefSharedRef } } -} -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime /// name where required. pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { @@ -995,4 +995,173 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let span = self.body.source_info(borrow.reserve_location).span; self.borrow_spans(span, borrow.reserve_location) } + + fn explain_captures( + &mut self, + err: &mut Diagnostic, + span: Span, + move_span: Span, + move_spans: UseSpans<'tcx>, + moved_place: Place<'tcx>, + used_place: Option>, + partially_str: &str, + loop_message: &str, + move_msg: &str, + is_loop_move: bool, + maybe_reinitialized_locations_is_empty: bool, + ) { + if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { + let place_name = self + .describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "value".to_owned()); + match kind { + CallKind::FnCall { fn_trait_id, .. } + if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => + { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this call{}", + place_name, partially_str, loop_message + ), + ); + err.span_note( + var_span, + "this value implements `FnOnce`, which causes it to be moved when called", + ); + } + CallKind::Operator { self_arg, .. } => { + let self_arg = self_arg.unwrap(); + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to usage in operator{}", + place_name, partially_str, loop_message + ), + ); + if self.fn_self_span_reported.insert(fn_span) { + err.span_note( + // Check whether the source is accessible + if self + .infcx + .tcx + .sess + .source_map() + .span_to_snippet(self_arg.span) + .is_ok() + { + self_arg.span + } else { + fn_call_span + }, + "calling this operator moves the left-hand side", + ); + } + } + CallKind::Normal { self_arg, desugaring, is_option_or_result } => { + let self_arg = self_arg.unwrap(); + if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { + let ty = moved_place.ty(self.body, self.infcx.tcx).ty; + let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { + Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { + type_known_to_meet_bound_modulo_regions( + &infcx, + self.param_env, + infcx.tcx.mk_imm_ref( + infcx.tcx.lifetimes.re_erased, + infcx.tcx.erase_regions(ty), + ), + def_id, + DUMMY_SP, + ) + }), + _ => false, + }; + if suggest { + err.span_suggestion_verbose( + move_span.shrink_to_lo(), + &format!( + "consider iterating over a slice of the `{}`'s content to \ + avoid moving into the `for` loop", + ty, + ), + "&".to_string(), + Applicability::MaybeIncorrect, + ); + } + + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this implicit call to `.into_iter()`{}", + place_name, partially_str, loop_message + ), + ); + // If we have a `&mut` ref, we need to reborrow. + if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place + .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind()) + { + // If we are in a loop this will be suggested later. + if !is_loop_move { + err.span_suggestion_verbose( + move_span.shrink_to_lo(), + &format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the mutable reference".to_string()), + ), + "&mut *".to_string(), + Applicability::MachineApplicable, + ); + } + } + } else { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this method call{}", + place_name, partially_str, loop_message + ), + ); + } + if is_option_or_result && maybe_reinitialized_locations_is_empty { + err.span_suggestion_verbose( + fn_call_span.shrink_to_lo(), + "consider calling `.as_ref()` to borrow the type's contents", + "as_ref().".to_string(), + Applicability::MachineApplicable, + ); + } + // Avoid pointing to the same function in multiple different + // error messages. + if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { + err.span_note( + self_arg.span, + &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) + ); + } + } + // Other desugarings takes &self, which cannot cause a move + _ => {} + } + } else { + if move_span != span || !loop_message.is_empty() { + err.span_label( + move_span, + format!("value {}moved{} here{}", partially_str, move_msg, loop_message), + ); + } + // If the move error occurs due to a loop, don't show + // another message for the same span + if loop_message.is_empty() { + move_spans.var_span_label( + err, + format!("variable {}moved due to use{}", partially_str, move_spans.describe()), + "moved", + ); + } + } + } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 19091569b4d27..f76ec031aa9e2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,15 +1,12 @@ -use rustc_const_eval::util::CallDesugaringKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty; use rustc_mir_dataflow::move_paths::{ IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, }; -use rustc_span::{sym, Span, DUMMY_SP}; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; +use rustc_span::{sym, Span}; -use crate::diagnostics::{CallKind, UseSpans}; +use crate::diagnostics::UseSpans; use crate::prefixes::PrefixSet; use crate::MirBorrowckCtxt; @@ -409,34 +406,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ".as_ref()".to_string(), Applicability::MaybeIncorrect, ); - } else if let Some(UseSpans::FnSelfUse { - kind: - CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. }, - .. - }) = use_spans - { - let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { - Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { - type_known_to_meet_bound_modulo_regions( - &infcx, - self.param_env, - infcx - .tcx - .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)), - def_id, - DUMMY_SP, - ) - }), - _ => false, - }; - if suggest { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!("consider iterating over a slice of the `{}`'s content", ty), - "&".to_string(), - Applicability::MaybeIncorrect, - ); - } + } else if let Some(use_spans) = use_spans { + self.explain_captures( + &mut err, span, span, use_spans, move_place, None, "", "", "", false, true, + ); } err } @@ -491,11 +464,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); - use_spans.var_span_label( - err, - format!("move occurs due to use{}", use_spans.describe()), - "moved", - ); } } } diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr index e2c8073241487..d88185af778f1 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr @@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait + | | | move out of `foo` occurs here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr index e2c8073241487..d88185af778f1 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr @@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait + | | | move out of `foo` occurs here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 257ec3fbb7fa2..f81b34a641bf0 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -8,8 +8,8 @@ LL | let _g = to_fn_mut(|| { LL | | let _h = to_fn_once(move || -> isize { *bar }); | | ^^^^^^^^^^^^^^^^ ---- | | | | + | | | variable moved due to use in closure | | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait - | | | move occurs due to use in closure | | move out of `bar` occurs here LL | | }); | |_____- captured by this `FnMut` closure diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 7974506507097..800f30b34e589 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -2,7 +2,16 @@ error[E0507]: cannot move out of an `Rc` --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 | LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^^----------- + | | | + | | value moved due to this method call + | move occurs because value has type `Vec`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves value + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr index 540f7f8a48477..c4ce7e62fda82 100644 --- a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr +++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr @@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-mutation-in-guard.rs:6:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait + | | | move out of `foo` occurs here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index 1663ce81d6cf4..3ea7226200362 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -6,10 +6,18 @@ LL | let y = vec![format!("World")]; LL | call(|| { | __________- LL | | y.into_iter(); - | | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait + | | ^ ----------- `y` moved due to this method call + | | | + | | move occurs because `y` has type `Vec`, which does not implement the `Copy` trait LL | | LL | | }); | |_____- captured by this `Fn` closure + | +note: this function takes ownership of the receiver `self`, which moves `y` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr index 3837e206169d4..ce8d1ef03493c 100644 --- a/src/test/ui/error-codes/E0507.stderr +++ b/src/test/ui/error-codes/E0507.stderr @@ -2,7 +2,16 @@ error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>` --> $DIR/E0507.rs:12:5 | LL | x.borrow().nothing_is_true(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait + | ^^^^^^^^^^^----------------- + | | | + | | value moved due to this method call + | move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves value + --> $DIR/E0507.rs:6:24 + | +LL | fn nothing_is_true(self) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr index 7895cefb4cb2e..a0d32616f83b7 100644 --- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr @@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19 | LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait + | | | move out of `foo` occurs here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index 6f345f56d1aa1..e5b671d7b7ab0 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -4,10 +4,7 @@ error[E0382]: borrow of moved value: `bad_letters` LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; | --------------- move occurs because `bad_letters` has type `Vec`, which does not implement the `Copy` trait LL | for l in bad_letters { - | ----------- - | | - | `bad_letters` moved due to this implicit call to `.into_iter()` - | help: consider borrowing to avoid moving into the for loop: `&bad_letters` + | ----------- `bad_letters` moved due to this implicit call to `.into_iter()` ... LL | bad_letters.push('s'); | ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move @@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `bad_let | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop + | +LL | for l in &bad_letters { + | + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index e0da3fd5195cb..ef178bbd15538 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -4,10 +4,7 @@ error[E0382]: use of moved value: `orig` LL | let orig = vec![true]; | ---- move occurs because `orig` has type `Vec`, which does not implement the `Copy` trait LL | for _val in orig {} - | ---- - | | - | `orig` moved due to this implicit call to `.into_iter()` - | help: consider borrowing to avoid moving into the for loop: `&orig` + | ---- `orig` moved due to this implicit call to `.into_iter()` LL | let _closure = || orig; | ^^ ---- use occurs due to use in closure | | @@ -18,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `orig` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop + | +LL | for _val in &orig {} + | + error: aborting due to previous error diff --git a/src/test/ui/loops/issue-82916.stderr b/src/test/ui/loops/issue-82916.stderr index ad42cce71f686..57d76016c4539 100644 --- a/src/test/ui/loops/issue-82916.stderr +++ b/src/test/ui/loops/issue-82916.stderr @@ -4,10 +4,7 @@ error[E0382]: use of moved value: `x` LL | fn foo(x: Vec) { | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | for y in x { - | - - | | - | `x` moved due to this implicit call to `.into_iter()` - | help: consider borrowing to avoid moving into the for loop: `&x` + | - `x` moved due to this implicit call to `.into_iter()` ... LL | let z = x; | ^ value used here after move @@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `x` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop + | +LL | for y in &x { + | + error: aborting due to previous error diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr index db4c3979e3ad6..baa87e3e9fdb2 100644 --- a/src/test/ui/moves/issue-46099-move-in-macro.stderr +++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr @@ -4,10 +4,7 @@ error[E0382]: use of moved value: `b` LL | let b = Box::new(true); | - move occurs because `b` has type `Box`, which does not implement the `Copy` trait LL | test!({b}); - | ^ - | | - | value moved here - | value used here after move + | ^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index 57be5fb4d8a59..3a686121a9283 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -119,12 +119,14 @@ error[E0382]: use of moved value: `implicit_into_iter` LL | let implicit_into_iter = vec![true]; | ------------------ move occurs because `implicit_into_iter` has type `Vec`, which does not implement the `Copy` trait LL | for _val in implicit_into_iter {} - | ------------------ - | | - | `implicit_into_iter` moved due to this implicit call to `.into_iter()` - | help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter` + | ------------------ `implicit_into_iter` moved due to this implicit call to `.into_iter()` LL | implicit_into_iter; | ^^^^^^^^^^^^^^^^^^ value used here after move + | +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop + | +LL | for _val in &implicit_into_iter {} + | + error[E0382]: use of moved value: `explicit_into_iter` --> $DIR/move-fn-self-receiver.rs:67:5 diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index ea350926b1519..8d636c11b78c7 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -5,10 +5,7 @@ LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (_, 2) if take(x) => (), - | ^ - | | - | value moved here - | value used here after move + | ^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr index df6d65056acd2..c0fb5f65382dc 100644 --- a/src/test/ui/nll/match-guards-always-borrow.stderr +++ b/src/test/ui/nll/match-guards-always-borrow.stderr @@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/match-guards-always-borrow.rs:8:14 | LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait + | | | move out of `foo` occurs here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 28c319b659765..1059e3d1525aa 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -13,16 +13,17 @@ LL | let a = vec![1, 2, 3]; | - move occurs because `a` has type `Vec`, which does not implement the `Copy` trait LL | for i in &a { LL | for j in a { - | ^ - | | - | `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop - | help: consider borrowing to avoid moving into the for loop: `&a` + | ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop | note: this function takes ownership of the receiver `self`, which moves `a` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop + | +LL | for j in &a { + | + error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr index c39363f762bdd..88be9e30a7641 100644 --- a/src/test/ui/suggestions/for-i-in-vec.stderr +++ b/src/test/ui/suggestions/for-i-in-vec.stderr @@ -2,9 +2,17 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference --> $DIR/for-i-in-vec.rs:11:18 | LL | for _ in self.v { - | ^^^^^^ move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait + | ^^^^^^ + | | + | `self.v` moved due to this implicit call to `.into_iter()` + | move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait | -help: consider iterating over a slice of the `Vec`'s content +note: this function takes ownership of the receiver `self`, which moves `self.v` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ +help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop | LL | for _ in &self.v { | + @@ -13,9 +21,12 @@ error[E0507]: cannot move out of `self.h` which is behind a shared reference --> $DIR/for-i-in-vec.rs:13:18 | LL | for _ in self.h { - | ^^^^^^ move occurs because `self.h` has type `HashMap`, which does not implement the `Copy` trait + | ^^^^^^ + | | + | `self.h` moved due to this implicit call to `.into_iter()` + | move occurs because `self.h` has type `HashMap`, which does not implement the `Copy` trait | -help: consider iterating over a slice of the `HashMap`'s content +help: consider iterating over a slice of the `HashMap`'s content to avoid moving into the `for` loop | LL | for _ in &self.h { | + @@ -24,9 +35,17 @@ error[E0507]: cannot move out of a shared reference --> $DIR/for-i-in-vec.rs:21:19 | LL | for loader in *LOADERS { - | ^^^^^^^^ move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait + | ^^^^^^^^ + | | + | value moved due to this implicit call to `.into_iter()` + | move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves value + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -help: consider iterating over a slice of the `Vec<&u8>`'s content +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ +help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid moving into the `for` loop | LL | for loader in &*LOADERS { | + diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr index a0ce7d05b4d48..16cbbaba512a4 100644 --- a/src/test/ui/suggestions/option-content-move2.stderr +++ b/src/test/ui/suggestions/option-content-move2.stderr @@ -12,8 +12,8 @@ LL | | LL | | var = Some(NotCopyable); | | --- | | | + | | variable moved due to use in closure | | move occurs because `var` has type `Option`, which does not implement the `Copy` trait - | | move occurs due to use in closure LL | | } LL | | }); | |_____- captured by this `FnMut` closure