diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2020-06-11 13:48:46 -0400 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2020-06-26 16:28:09 -0400 |
| commit | fa6a61c68930b390407d73e0ba71f2af5555f0f0 (patch) | |
| tree | 9d1ad6feeb72a826ca906a1a25a5271f5242a9b7 | |
| parent | 36ac08e2643dc5cc035031007a8a36f4c87d3543 (diff) | |
| download | rust-fa6a61c68930b390407d73e0ba71f2af5555f0f0.tar.gz rust-fa6a61c68930b390407d73e0ba71f2af5555f0f0.zip | |
Explain move errors that occur due to method calls involving `self`
This is a re-attempt of #72389 (which was reverted in #73594) Instead of using `ExpnKind::Desugaring` to represent operators, this PR checks the lang item directly.
38 files changed, 745 insertions, 102 deletions
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index d2c4478ccfe..90a3a5ec64e 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; +use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_target::asm; use std::collections::hash_map::Entry; @@ -1361,9 +1361,14 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::Expr<'hir> { + let orig_head_span = head.span; // expand <head> let mut head = self.lower_expr_mut(head); - let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); + let desugared_span = self.mark_span_with_reason( + DesugaringKind::ForLoop(ForLoopLoc::Head), + orig_head_span, + None, + ); head.span = desugared_span; let iter = Ident::with_dummy_span(sym::iter); @@ -1458,10 +1463,16 @@ impl<'hir> LoweringContext<'_, 'hir> { // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); + let into_iter_span = self.mark_span_with_reason( + DesugaringKind::ForLoop(ForLoopLoc::IntoIter), + orig_head_span, + None, + ); + // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` let into_iter_expr = { let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter]; - self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head]) + self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head]) }; let match_expr = self.arena.alloc(self.expr_match( diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index cd6f034f7a5..5aaf219b315 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -21,11 +21,26 @@ use rustc_span::Span; use lazy_static::lazy_static; +pub enum LangItemGroup { + Op, +} + +const NUM_GROUPS: usize = 1; + +macro_rules! expand_group { + () => { + None + }; + ($group:expr) => { + Some($group) + }; +} + // The actual lang items defined come at the end of this file in one handy table. // So you probably just want to nip down to the end. macro_rules! language_item_table { ( - $( $variant:ident, $name:expr, $method:ident, $target:expr; )* + $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )* ) => { enum_from_u32! { @@ -45,6 +60,13 @@ macro_rules! language_item_table { $( $variant => $name, )* } } + + pub fn group(self) -> Option<LangItemGroup> { + use LangItemGroup::*; + match self { + $( $variant => expand_group!($($group)*), )* + } + } } #[derive(HashStable_Generic)] @@ -54,6 +76,9 @@ macro_rules! language_item_table { pub items: Vec<Option<DefId>>, /// Lang items that were not found during collection. pub missing: Vec<LangItem>, + /// Mapping from `LangItemGroup` discriminants to all + /// `DefId`s of lang items in that group. + pub groups: [Vec<DefId>; NUM_GROUPS], } impl LanguageItems { @@ -64,6 +89,7 @@ macro_rules! language_item_table { Self { items: vec![$(init_none($variant)),*], missing: Vec::new(), + groups: [vec![]; NUM_GROUPS], } } @@ -79,6 +105,10 @@ macro_rules! language_item_table { self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) } + pub fn group(&self, group: LangItemGroup) -> &[DefId] { + self.groups[group as usize].as_ref() + } + $( /// Returns the corresponding `DefId` for the lang item #[doc = $name] @@ -171,30 +201,30 @@ language_item_table! { CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; - AddTraitLangItem, "add", add_trait, Target::Trait; - SubTraitLangItem, "sub", sub_trait, Target::Trait; - MulTraitLangItem, "mul", mul_trait, Target::Trait; - DivTraitLangItem, "div", div_trait, Target::Trait; - RemTraitLangItem, "rem", rem_trait, Target::Trait; - NegTraitLangItem, "neg", neg_trait, Target::Trait; - NotTraitLangItem, "not", not_trait, Target::Trait; - BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait; - BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait; - BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait; - ShlTraitLangItem, "shl", shl_trait, Target::Trait; - ShrTraitLangItem, "shr", shr_trait, Target::Trait; - AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait; - SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait; - MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait; - DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait; - RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait; - BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait; - BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait; - BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait; - ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait; - ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; - IndexTraitLangItem, "index", index_trait, Target::Trait; - IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; + AddTraitLangItem(Op), "add", add_trait, Target::Trait; + SubTraitLangItem(Op), "sub", sub_trait, Target::Trait; + MulTraitLangItem(Op), "mul", mul_trait, Target::Trait; + DivTraitLangItem(Op), "div", div_trait, Target::Trait; + RemTraitLangItem(Op), "rem", rem_trait, Target::Trait; + NegTraitLangItem(Op), "neg", neg_trait, Target::Trait; + NotTraitLangItem(Op), "not", not_trait, Target::Trait; + BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait; + BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait; + BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait; + ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait; + ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait; + AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait; + SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait; + MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait; + DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait; + RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait; + BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait; + BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait; + BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait; + ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait; + ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait; + IndexTraitLangItem(Op), "index", index_trait, Target::Trait; + IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait; UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; VaListTypeLangItem, "va_list", va_list, Target::Struct; diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 04d941fb8a7..1687bcc1556 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let msg = if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.desugaring_kind() { None => format!("consider giving `{}` {}", simple_ident, suffix), - Some(DesugaringKind::ForLoop) => { + Some(DesugaringKind::ForLoop(_)) => { "the element type for this iterator is not specified".to_string() } _ => format!("this needs {}", suffix), diff --git a/src/librustc_middle/lint.rs b/src/librustc_middle/lint.rs index 27239b4ad2e..bb62c1bb824 100644 --- a/src/librustc_middle/lint.rs +++ b/src/librustc_middle/lint.rs @@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>( pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false, ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 60a1fe0b198..e85f69554d0 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -24,7 +24,8 @@ use crate::borrow_check::{ }; use super::{ - explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans, + explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, + RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -150,11 +151,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("value moved{} here, in previous iteration of loop", move_msg), ); } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); - move_spans.var_span_label( - &mut err, - format!("variable moved due to use{}", move_spans.describe()), - ); + 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 { + FnSelfUseKind::FnOnceCall => { + err.span_label( + fn_call_span, + &format!("{} moved due to this call", place_name), + ); + err.span_note( + var_span, + "this value implements `FnOnce`, which causes it to be moved when called", + ); + } + FnSelfUseKind::Operator { self_arg } => { + err.span_label( + fn_call_span, + &format!("{} moved due to usage in operator", place_name), + ); + if self.fn_self_span_reported.insert(fn_span) { + err.span_note( + self_arg.span, + "calling this operator moves the left-hand side", + ); + } + } + FnSelfUseKind::Normal { self_arg, implicit_into_iter } => { + if implicit_into_iter { + err.span_label( + fn_call_span, + &format!( + "{} moved due to this implicit call to `.into_iter()`", + place_name + ), + ); + } else { + err.span_label( + fn_call_span, + &format!("{} moved due to this method call", place_name), + ); + } + // Avoid pointing to the same function in multiple different + // error messages + if self.fn_self_span_reported.insert(self_arg.span) { + err.span_note( + self_arg.span, + &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name) + ); + } + } + } + } else { + err.span_label(move_span, format!("value moved{} here", move_msg)); + move_spans.var_span_label( + &mut err, + format!("variable moved due to use{}", move_spans.describe()), + ); + } } if let UseSpans::PatUse(span) = move_spans { err.span_suggestion_verbose( @@ -170,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { + if let 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) { err.span_suggestion( diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 849fd63998d..b591b938b5a 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -509,7 +509,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Used in a closure. (LaterUseKind::ClosureCapture, var_span) } - UseSpans::PatUse(span) | UseSpans::OtherUse(span) => { + UseSpans::PatUse(span) + | UseSpans::OtherUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } => { let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index 388076a9d60..e94952e1c54 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -4,6 +4,7 @@ use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItemGroup; use rustc_hir::GeneratorKind; use rustc_middle::mir::{ AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, @@ -11,7 +12,11 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::{ + hygiene::{DesugaringKind, ForLoopLoc}, + symbol::sym, + Span, +}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -33,6 +38,7 @@ crate use mutability_errors::AccessKind; crate use outlives_suggestion::OutlivesSuggestionBuilder; crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; crate use region_name::{RegionName, RegionNameSource}; +use rustc_span::symbol::Ident; pub(super) struct IncludingDowncast(pub(super) bool); @@ -529,18 +535,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } -// The span(s) associated to a use of a place. +/// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) enum UseSpans { - // The access is caused by capturing a variable for a closure. + /// The access is caused by capturing a variable for a closure. ClosureUse { - // This is true if the captured variable was from a generator. + /// This is true if the captured variable was from a generator. generator_kind: Option<GeneratorKind>, - // The span of the args of the closure, including the `move` keyword if - // it's present. + /// The span of the args of the closure, including the `move` keyword if + /// it's present. args_span: Span, - // The span of the first use of the captured variable inside the closure. + /// The span of the first use of the captured variable inside the closure. + var_span: Span, + }, + /// The access is caused by using a variable as the receiver of a method + /// that takes 'self' + FnSelfUse { + /// The span of the variable being moved var_span: Span, + /// The span of the method call on the variable + fn_call_span: Span, + /// The definition span of the method being called + fn_span: Span, + kind: FnSelfUseKind, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -548,11 +565,22 @@ pub(super) enum UseSpans { OtherUse(Span), } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum FnSelfUseKind { + /// A normal method call of the form `receiver.foo(a, b, c)` + Normal { self_arg: Ident, implicit_into_iter: bool }, + /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` + FnOnceCall, + /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) + Operator { self_arg: Ident }, +} + impl UseSpans { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, } } @@ -561,6 +589,7 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, } } @@ -631,6 +660,7 @@ impl UseSpans { match self { closure @ UseSpans::ClosureUse { .. } => closure, UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), + fn_self @ UseSpans::FnSelfUse { .. } => fn_self, } } } @@ -733,25 +763,112 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind { - let def_id = match kind { + match kind { box AggregateKind::Closure(def_id, _) - | box AggregateKind::Generator(def_id, _, _) => def_id, - _ => return OtherUse(stmt.source_info.span), + | box AggregateKind::Generator(def_id, _, _) => { + debug!("move_spans: def_id={:?} places={:?}", def_id, places); + if let Some((args_span, generator_kind, var_span)) = + self.closure_span(*def_id, moved_place, places) + { + return ClosureUse { generator_kind, args_span, var_span }; + } + } + _ => {} + } + } + + let normal_ret = + if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { + PatUse(stmt.source_info.span) + } else { + OtherUse(stmt.source_info.span) }; - debug!("move_spans: def_id={:?} places={:?}", def_id, places); - if let Some((args_span, generator_kind, var_span)) = - self.closure_span(*def_id, moved_place, places) - { - return ClosureUse { generator_kind, args_span, var_span }; + // We are trying to find MIR of the form: + // ``` + // _temp = _moved_val; + // ... + // FnSelfCall(_temp, ...) + // ``` + // + // where `_moved_val` is the place we generated the move error for, + // `_temp` is some other local, and `FnSelfCall` is a function + // that has a `self` parameter. + + let target_temp = match stmt.kind { + StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => { + temp.as_local().unwrap() } - } + _ => return normal_ret, + }; - if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { - PatUse(stmt.source_info.span) - } else { - OtherUse(stmt.source_info.span) + debug!("move_spans: target_temp = {:?}", target_temp); + + if let Some(Terminator { + kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. }, + .. + }) = &self.body[location.block].terminator + { + let mut method_did = None; + if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { + if let ty::FnDef(def_id, _) = ty.kind { + debug!("move_spans: fn = {:?}", def_id); + if let Some(ty::AssocItem { fn_has_self_parameter, .. }) = + self.infcx.tcx.opt_associated_item(def_id) + { + if *fn_has_self_parameter { + method_did = Some(def_id); + } + } + } + } + + let tcx = self.infcx.tcx; + let method_did = if let Some(did) = method_did { did } else { return normal_ret }; + + if let [Operand::Move(self_place), ..] = **args { + if self_place.as_local() == Some(target_temp) { + let parent = tcx.parent(method_did); + let is_fn_once = parent == tcx.lang_items().fn_once_trait(); + let is_operator = !from_hir_call + && parent.map_or(false, |p| { + tcx.lang_items().group(LangItemGroup::Op).contains(&p) + }); + let fn_call_span = *fn_span; + + let self_arg = tcx.fn_arg_names(method_did)[0]; + + let kind = if is_fn_once { + FnSelfUseKind::FnOnceCall + } else if is_operator { + FnSelfUseKind::Operator { self_arg } + } else { + debug!( + "move_spans: method_did={:?}, fn_call_span={:?}", + method_did, fn_call_span + ); + let implicit_into_iter = matches!( + fn_call_span.desugaring_kind(), + Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + FnSelfUseKind::Normal { self_arg, implicit_into_iter } + }; + + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span, + fn_span: self + .infcx + .tcx + .sess + .source_map() + .guess_head_span(self.infcx.tcx.def_span(method_did)), + kind, + }; + } + } } + return normal_ret; } /// Finds the span of arguments of a closure (within `maybe_closure_span`) diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index b49e4187fb8..4883b08e424 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -408,7 +408,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { format!("{}.as_ref()", snippet), Applicability::MaybeIncorrect, ); - } else if span.is_desugaring(DesugaringKind::ForLoop) + } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) && self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) { // FIXME: suggest for anything that implements `IntoIterator`. diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 4d4b6fb9386..b4bc89e827d 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -365,7 +365,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); match opt_desugaring_kind { // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop) => Some(( + Some(DesugaringKind::ForLoop(_)) => Some(( false, opt_assignment_rhs_span.unwrap(), format!( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 03b663eb750..83691d439eb 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -278,6 +278,7 @@ fn do_mir_borrowck<'a, 'tcx>( move_data: &move_data, location_table: &LocationTable::new(promoted_body), movable_generator, + fn_self_span_reported: Default::default(), locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), @@ -311,6 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>( location_table, movable_generator, locals_are_invalidated_at_exit, + fn_self_span_reported: Default::default(), access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), reservation_warnings: Default::default(), @@ -487,6 +489,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { // but it is currently inconvenient to track down the `BorrowIndex` // at the time we detect and report a reservation error. reservation_error_reported: FxHashSet<Place<'tcx>>, + /// This fields keeps track of the `Span`s that we have + /// used to report extra information for `FnSelfUse`, to avoid + /// unnecessarily verbose errors. + fn_self_span_reported: FxHashSet<Span>, /// Migration warnings to be reported for #56254. We delay reporting these /// so that we can suppress the warning if there's a corresponding error /// for the activation of the borrow. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 19337c520f9..ba538803468 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -506,6 +506,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // This is basically `force_bits`. let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok()); if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { + debug!("check_binary_op: reporting assert for {:?}", source_info); self.report_assert_as_lint( lint::builtin::ARITHMETIC_OVERFLOW, source_info, diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index f4167c8644e..0be37cb0960 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -102,7 +102,8 @@ impl LanguageItemCollector<'tcx> { // Check for duplicates. if let Some(original_def_id) = self.items.items[item_index] { if original_def_id != item_def_id { - let name = LangItem::from_u32(item_index as u32).unwrap().name(); + let lang_item = LangItem::from_u32(item_index as u32).unwrap(); + let name = lang_item.name(); let mut err = match self.tcx.hir().span_if_local(item_def_id) { Some(span) => struct_span_err!( self.tcx.sess, @@ -152,6 +153,9 @@ impl LanguageItemCollector<'tcx> { // Matched. self.items.items[item_index] = Some(item_def_id); + if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() { + self.items.groups[group as usize].push(item_def_id); + } } } diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs index c0fb84e741f..60bbdd0495c 100644 --- a/src/librustc_span/hygiene.rs +++ b/src/librustc_span/hygiene.rs @@ -822,7 +822,14 @@ pub enum DesugaringKind { OpaqueTy, Async, Await, - ForLoop, + ForLoop(ForLoopLoc), +} + +/// A location in the desugaring of a `for` loop +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)] +pub enum ForLoopLoc { + Head, + IntoIter, } impl DesugaringKind { @@ -835,7 +842,7 @@ impl DesugaringKind { DesugaringKind::QuestionMark => "operator `?`", DesugaringKind::TryBlock => "`try` block", DesugaringKind::OpaqueTy => "`impl Trait`", - DesugaringKind::ForLoop => "`for` loop", + DesugaringKind::ForLoop(_) => "`for` loop", } } } diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 96240066834..dcd2e83b747 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -30,8 +30,9 @@ use source_map::SourceMap; pub mod edition; use edition::Edition; pub mod hygiene; +pub use hygiene::SyntaxContext; use hygiene::Transparency; -pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext}; +pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind}; pub mod def_id; use def_id::{CrateNum, DefId, LOCAL_CRATE}; mod span_encoding; diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr index acdc03e3726..addc8a0efe1 100644 --- a/src/test/ui/binop/binop-consume-args.stderr +++ b/src/test/ui/binop/binop-consume-args.stderr @@ -4,10 +4,15 @@ error[E0382]: use of moved value: `lhs` LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs + rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -35,10 +40,15 @@ error[E0382]: use of moved value: `lhs` LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs - rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn sub(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -66,10 +76,15 @@ error[E0382]: use of moved value: `lhs` LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs * rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn mul(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -97,10 +112,15 @@ error[E0382]: use of moved value: `lhs` LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs / rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn div(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -128,10 +148,15 @@ error[E0382]: use of moved value: `lhs` LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs % rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn rem(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -159,10 +184,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs & rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitand(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -190,10 +220,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs | rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitor(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -221,10 +256,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs ^ rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitxor(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -252,10 +292,15 @@ error[E0382]: use of moved value: `lhs` LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs << rhs; - | --- value moved here + | ---------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn shl(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -283,10 +328,15 @@ error[E0382]: use of moved value: `lhs` LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs >> rhs; - | --- value moved here + | ---------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn shr(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) { diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index 6d5ac9cab30..97b70efe20e 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -1,14 +1,21 @@ error[E0382]: use of moved value: `x` --> $DIR/binop-move-semantics.rs:8:5 | -LL | fn double_move<T: Add<Output=()>>(x: T) { - | - move occurs because `x` has type `T`, which does not implement the `Copy` trait -LL | x - | - value moved here -LL | + -LL | x; - | ^ value used here after move +LL | fn double_move<T: Add<Output=()>>(x: T) { + | - move occurs because `x` has type `T`, which does not implement the `Copy` trait +LL | / x +LL | | + +LL | | x; + | | ^ + | | | + | |_____value used here after move + | `x` moved due to usage in operator + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn double_move<T: Add<Output=()> + Copy>(x: T) { diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr index a51cda548ef..bc1721944fb 100644 --- a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr +++ b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr @@ -22,10 +22,15 @@ error[E0382]: use of moved value: `f` LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) { | - move occurs because `f` has type `F`, which does not implement the `Copy` trait LL | f(1, 2); - | - value moved here + | ------- `f` moved due to this call LL | f(1, 2); | ^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/borrowck-unboxed-closures.rs:11:5 + | +LL | f(1, 2); + | ^ help: consider further restricting this bound | LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) { diff --git a/src/test/ui/closure_context/issue-42065.stderr b/src/test/ui/closure_context/issue-42065.stderr index 69d98654048..896bb6dc6be 100644 --- a/src/test/ui/closure_context/issue-42065.stderr +++ b/src/test/ui/closure_context/issue-42065.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/issue-42065.rs:11:5 | LL | debug_dump_dict(); - | --------------- value moved here + | ----------------- `debug_dump_dict` moved due to this call LL | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `di | LL | for (key, value) in dict { | ^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/issue-42065.rs:10:5 + | +LL | debug_dump_dict(); + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index 97816a76004..614e69e89f6 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -4,10 +4,16 @@ error[E0382]: borrow of moved value: `some_vec` LL | let some_vec = vec!["hi"]; | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait LL | some_vec.into_iter(); - | -------- value moved here + | ----------- `some_vec` moved due to this method call LL | { LL | println!("{:?}", some_vec); | ^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec` + --> $SRC_DIR/libcore/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/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr index 2283b1275d0..b759aa45e3e 100644 --- a/src/test/ui/issues/issue-12127.stderr +++ b/src/test/ui/issues/issue-12127.stderr @@ -2,10 +2,15 @@ error[E0382]: use of moved value: `f` --> $DIR/issue-12127.rs:11:9 | LL | f(); - | - value moved here + | --- `f` moved due to this call LL | f(); | ^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/issue-12127.rs:10:9 + | +LL | f(); + | ^ = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box<isize>]`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index ccaa6334856..4fb805b37e0 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,4 +3,5 @@ use std::collections::HashMap; fn main() { for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch //~^ ERROR type mismatch + //~| ERROR type mismatch } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 734ae78f362..20335d2cdd6 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -17,6 +17,16 @@ LL | for _ in HashMap::new().iter().cloned() {} found reference `&_` = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>` -error: aborting due to 2 previous errors +error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_` + --> $DIR/issue-33941.rs:4:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | + = note: expected tuple `(&_, &_)` + found reference `&_` + = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr index 6cfed20f43a..b4cc1a0aa7e 100644 --- a/src/test/ui/issues/issue-34721.stderr +++ b/src/test/ui/issues/issue-34721.stderr @@ -5,14 +5,19 @@ LL | pub fn baz<T: Foo>(x: T) -> T { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait LL | if 0 == 1 { LL | bar::bar(x.zero()) - | - value moved here + | ------ `x` moved due to this method call LL | } else { LL | x.zero() - | - value moved here + | ------ `x` moved due to this method call LL | }; LL | x.zero() | ^ value used here after move | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $DIR/issue-34721.rs:4:13 + | +LL | fn zero(self) -> Self; + | ^^^^ help: consider further restricting this bound | LL | pub fn baz<T: Foo + Copy>(x: T) -> T { diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index 8523a6f6548..ba43f2d33ee 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -6,11 +6,17 @@ LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; LL | for l in bad_letters { | ----------- | | - | value moved here + | `bad_letters` moved due to this implicit call to `.into_iter()` | help: consider borrowing to avoid moving into the for loop: `&bad_letters` ... LL | bad_letters.push('s'); | ^^^^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters` + --> $SRC_DIR/libcore/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/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index 3c685dc8d08..2c337bae130 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -6,12 +6,18 @@ LL | let orig = vec![true]; LL | for _val in orig {} | ---- | | - | value moved here + | `orig` moved due to this implicit call to `.into_iter()` | help: consider borrowing to avoid moving into the for loop: `&orig` LL | let _closure = || orig; | ^^ ---- use occurs due to use in closure | | | value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `orig` + --> $SRC_DIR/libcore/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/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs new file mode 100644 index 00000000000..6107f53fa19 --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.rs @@ -0,0 +1,74 @@ +use std::pin::Pin; +use std::rc::Rc; +use std::ops::Add; + +struct Foo; + +impl Add for Foo { + type Output = (); + fn add(self, _rhs: Self) -> () {} +} + +impl Foo { + fn use_self(self) {} + fn use_box_self(self: Box<Self>) {} + fn use_pin_box_self(self: Pin<Box<Self>>) {} + fn use_rc_self(self: Rc<Self>) {} + fn use_mut_self(&mut self) -> &mut Self { self } +} + +struct Container(Vec<bool>); + +impl Container { + fn custom_into_iter(self) -> impl Iterator<Item = bool> { + self.0.into_iter() + } +} + +fn move_out(val: Container) { + val.0.into_iter().next(); + val.0; //~ ERROR use of moved + + let foo = Foo; + foo.use_self(); + foo; //~ ERROR use of moved + + let second_foo = Foo; + second_foo.use_self(); + second_foo; //~ ERROR use of moved + + let boxed_foo = Box::new(Foo); + boxed_foo.use_box_self(); + boxed_foo; //~ ERROR use of moved + + let pin_box_foo = Box::pin(Foo); + pin_box_foo.use_pin_box_self(); + pin_box_foo; //~ ERROR use of moved + + let mut mut_foo = Foo; + let ret = mut_foo.use_mut_self(); + mut_foo; //~ ERROR cannot move out + ret; + + let rc_foo = Rc::new(Foo); + rc_foo.use_rc_self(); + rc_foo; //~ ERROR use of moved + + let foo_add = Foo; + foo_add + Foo; + foo_add; //~ ERROR use of moved + + let implicit_into_iter = vec![true]; + for _val in implicit_into_iter {} + implicit_into_iter; //~ ERROR use of moved + + let explicit_into_iter = vec![true]; + for _val in explicit_into_iter.into_iter() {} + explicit_into_iter; //~ ERROR use of moved + + let container = Container(vec![]); + for _val in container.custom_into_iter() {} + container; //~ ERROR use of moved +} + +fn main() {} diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr new file mode 100644 index 00000000000..4333e8a23e8 --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -0,0 +1,158 @@ +error[E0382]: use of moved value: `val.0` + --> $DIR/move-fn-self-receiver.rs:30:5 + | +LL | val.0.into_iter().next(); + | ----------- `val.0` moved due to this method call +LL | val.0; + | ^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + = note: move occurs because `val.0` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo` + --> $DIR/move-fn-self-receiver.rs:34:5 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo.use_self(); + | ---------- `foo` moved due to this method call +LL | foo; + | ^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `foo` + --> $DIR/move-fn-self-receiver.rs:13:17 + | +LL | fn use_self(self) {} + | ^^^^ + +error[E0382]: use of moved value: `second_foo` + --> $DIR/move-fn-self-receiver.rs:38:5 + | +LL | let second_foo = Foo; + | ---------- move occurs because `second_foo` has type `Foo`, which does not implement the `Copy` trait +LL | second_foo.use_self(); + | ---------- `second_foo` moved due to this method call +LL | second_foo; + | ^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:42:5 + | +LL | let boxed_foo = Box::new(Foo); + | --------- move occurs because `boxed_foo` has type `std::boxed::Box<Foo>`, which does not implement the `Copy` trait +LL | boxed_foo.use_box_self(); + | -------------- `boxed_foo` moved due to this method call +LL | boxed_foo; + | ^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:14:21 + | +LL | fn use_box_self(self: Box<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:46:5 + | +LL | let pin_box_foo = Box::pin(Foo); + | ----------- move occurs because `pin_box_foo` has type `std::pin::Pin<std::boxed::Box<Foo>>`, which does not implement the `Copy` trait +LL | pin_box_foo.use_pin_box_self(); + | ------------------ `pin_box_foo` moved due to this method call +LL | pin_box_foo; + | ^^^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:15:25 + | +LL | fn use_pin_box_self(self: Pin<Box<Self>>) {} + | ^^^^ + +error[E0505]: cannot move out of `mut_foo` because it is borrowed + --> $DIR/move-fn-self-receiver.rs:50:5 + | +LL | let ret = mut_foo.use_mut_self(); + | ------- borrow of `mut_foo` occurs here +LL | mut_foo; + | ^^^^^^^ move out of `mut_foo` occurs here +LL | ret; + | --- borrow later used here + +error[E0382]: use of moved value: `rc_foo` + --> $DIR/move-fn-self-receiver.rs:55:5 + | +LL | let rc_foo = Rc::new(Foo); + | ------ move occurs because `rc_foo` has type `std::rc::Rc<Foo>`, which does not implement the `Copy` trait +LL | rc_foo.use_rc_self(); + | ------------- `rc_foo` moved due to this method call +LL | rc_foo; + | ^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo` + --> $DIR/move-fn-self-receiver.rs:16:20 + | +LL | fn use_rc_self(self: Rc<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `foo_add` + --> $DIR/move-fn-self-receiver.rs:59:5 + | +LL | let foo_add = Foo; + | ------- move occurs because `foo_add` has type `Foo`, which does not implement the `Copy` trait +LL | foo_add + Foo; + | ------------- `foo_add` moved due to usage in operator +LL | foo_add; + | ^^^^^^^ value used here after move + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ + +error[E0382]: use of moved value: `implicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:63:5 + | +LL | let implicit_into_iter = vec![true]; + | ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec<bool>`, 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` +LL | implicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `explicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:67:5 + | +LL | let explicit_into_iter = vec![true]; + | ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait +LL | for _val in explicit_into_iter.into_iter() {} + | ----------- `explicit_into_iter` moved due to this method call +LL | explicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `container` + --> $DIR/move-fn-self-receiver.rs:71:5 + | +LL | let container = Container(vec![]); + | --------- move occurs because `container` has type `Container`, which does not implement the `Copy` trait +LL | for _val in container.custom_into_iter() {} + | ------------------ `container` moved due to this method call +LL | container; + | ^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `container` + --> $DIR/move-fn-self-receiver.rs:23:25 + | +LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> { + | ^^^^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index 71a3c4506ea..142feb280d1 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | consume(x.into_iter().next().unwrap()); - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x[0]); | ^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/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/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 67fae606c4e..ff98aab50c9 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -104,9 +104,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | let _y = x.into_iter().next().unwrap(); - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:83:11 @@ -114,9 +120,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | let _y = [x.into_iter().next().unwrap(); 1]; - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr index 7133a32431a..8761b5261d5 100644 --- a/src/test/ui/once-cant-call-twice-on-heap.stderr +++ b/src/test/ui/once-cant-call-twice-on-heap.stderr @@ -4,10 +4,15 @@ error[E0382]: use of moved value: `blk` LL | fn foo<F:FnOnce()>(blk: F) { | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); - | --- value moved here + | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/once-cant-call-twice-on-heap.rs:8:5 + | +LL | blk(); + | ^^^ help: consider further restricting this bound | LL | fn foo<F:FnOnce() + Copy>(blk: F) { diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr index 0b9aa61a765..ab6f0651846 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick` --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:10:5 | LL | tick(); - | ---- value moved here + | ------ `tick` moved due to this call LL | tick(); | ^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co | LL | let tick = || mem::drop(counter); | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr index 20773d561f9..8d70a2b1760 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick` --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:10:5 | LL | tick(); - | ---- value moved here + | ------ `tick` moved due to this call LL | tick(); | ^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co | LL | let tick = move || mem::drop(counter); | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index e0499cfe95c..dd54c222f64 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -4,11 +4,16 @@ error[E0382]: borrow of moved value: `x` LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait LL | !x; - | - value moved here + | -- `x` moved due to usage in operator LL | LL | x.clone(); | ^ value borrowed here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn not(self) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) { diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 110edab69be..906b543e421 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -37,10 +37,16 @@ error[E0382]: borrow of moved value: `y` LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); - | - value moved here + | ----- `y` moved due to this method call ... LL | println!("{}", &y); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `y` + --> $DIR/borrow-after-move.rs:4:12 + | +LL | fn foo(self) -> String; + | ^^^^ error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 5b936fb6447..49b2031c6b9 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -34,9 +34,15 @@ error[E0382]: use of moved value: `y` LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); - | - value moved here + | ----- `y` moved due to this method call LL | y.foo(); | ^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `y` + --> $DIR/double-move.rs:4:12 + | +LL | fn foo(self) -> String; + | ^^^^ error[E0382]: use of moved value: `x` --> $DIR/double-move.rs:45:9 diff --git a/src/test/ui/use/use-after-move-self-based-on-type.stderr b/src/test/ui/use/use-after-move-self-based-on-type.stderr index 9bf1175430c..b9440f4de07 100644 --- a/src/test/ui/use/use-after-move-self-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-self-based-on-type.stderr @@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self` LL | pub fn foo(self) -> isize { | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); - | ---- value moved here + | ----- `self` moved due to this method call LL | return self.x; | ^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `self` + --> $DIR/use-after-move-self-based-on-type.rs:15:16 + | +LL | pub fn bar(self) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-self.stderr b/src/test/ui/use/use-after-move-self.stderr index 3be0a65550b..3da53b024db 100644 --- a/src/test/ui/use/use-after-move-self.stderr +++ b/src/test/ui/use/use-after-move-self.stderr @@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self` LL | pub fn foo(self) -> isize { | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); - | ---- value moved here + | ----- `self` moved due to this method call LL | return *self.x; | ^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `self` + --> $DIR/use-after-move-self.rs:13:16 + | +LL | pub fn bar(self) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr index eeb594a21f3..ece63a2b819 100644 --- a/src/test/ui/walk-struct-literal-with.stderr +++ b/src/test/ui/walk-struct-literal-with.stderr @@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `start` LL | let start = Mine{test:"Foo".to_string(), other_val:0}; | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait LL | let end = Mine{other_val:1, ..start.make_string_bar()}; - | ----- value moved here + | ----------------- `start` moved due to this method call LL | println!("{}", start.test); | ^^^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `start` + --> $DIR/walk-struct-literal-with.rs:7:28 + | +LL | fn make_string_bar(mut self) -> Mine{ + | ^^^^ error: aborting due to previous error |
