Skip to content

Commit 372cb9b

Browse files
authored
Rollup merge of rust-lang#72389 - Aaron1011:feature/move-fn-self-msg, r=nikomatsakis
Explain move errors that occur due to method calls involving `self` When calling a method that takes `self` (e.g. `vec.into_iter()`), the method receiver is moved out of. If the method receiver is used again, a move error will be emitted:: ```rust fn main() { let a = vec![true]; a.into_iter(); a; } ``` emits ``` error[E0382]: use of moved value: `a` --> src/main.rs:4:5 | 2 | let a = vec![true]; | - move occurs because `a` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait 3 | a.into_iter(); | - value moved here 4 | a; | ^ value used here after move ``` However, the error message doesn't make it clear that the move is caused by the call to `into_iter`. This PR adds additional messages to move errors when the move is caused by using a value as the receiver of a `self` method:: ``` error[E0382]: use of moved value: `a` --> vec.rs:4:5 | 2 | let a = vec![true]; | - move occurs because `a` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait 3 | a.into_iter(); | ------------- value moved due to this method call 4 | a; | ^ value used here after move | note: this function takes `self`, which moves the receiver --> /home/aaron/repos/rust/src/libcore/iter/traits/collect.rs:239:5 | 239 | fn into_iter(self) -> Self::IntoIter; ``` TODO: - [x] Add special handling for `FnOnce/FnMut/Fn` - we probably don't want to point at the unstable trait methods - [x] Consider adding additional context for operations (e.g. `Shr::shr`) when the call was generated using the operator syntax (e.g. `a >> b`) - [x] Consider pointing to the method parent (impl or trait block) in addition to the method itself.
2 parents 5c61a8d + 4646e2d commit 372cb9b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+729
-103
lines changed

src/librustc_ast_lowering/expr.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
99
use rustc_errors::struct_span_err;
1010
use rustc_hir as hir;
1111
use rustc_hir::def::Res;
12-
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
12+
use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
1313
use rustc_span::symbol::{sym, Ident, Symbol};
1414
use rustc_target::asm;
1515
use std::collections::hash_map::Entry;
@@ -25,6 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
2525
}
2626

2727
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
28+
let mut span = e.span;
2829
ensure_sufficient_stack(|| {
2930
let kind = match e.kind {
3031
ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
@@ -53,6 +54,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
5354
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
5455
}
5556
ExprKind::Binary(binop, ref lhs, ref rhs) => {
57+
span = self.mark_span_with_reason(DesugaringKind::Operator, e.span, None);
5658
let binop = self.lower_binop(binop);
5759
let lhs = self.lower_expr(lhs);
5860
let rhs = self.lower_expr(rhs);
@@ -222,7 +224,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
222224
hir::Expr {
223225
hir_id: self.lower_node_id(e.id),
224226
kind,
225-
span: e.span,
227+
span,
226228
attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
227229
}
228230
})
@@ -237,6 +239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
237239
}
238240

239241
fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
242+
let span = self.mark_span_with_reason(DesugaringKind::Operator, b.span, None);
240243
Spanned {
241244
node: match b.node {
242245
BinOpKind::Add => hir::BinOpKind::Add,
@@ -258,7 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
258261
BinOpKind::Ge => hir::BinOpKind::Ge,
259262
BinOpKind::Gt => hir::BinOpKind::Gt,
260263
},
261-
span: b.span,
264+
span,
262265
}
263266
}
264267

@@ -1360,9 +1363,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
13601363
body: &Block,
13611364
opt_label: Option<Label>,
13621365
) -> hir::Expr<'hir> {
1366+
let orig_head_span = head.span;
13631367
// expand <head>
13641368
let mut head = self.lower_expr_mut(head);
1365-
let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
1369+
let desugared_span = self.mark_span_with_reason(
1370+
DesugaringKind::ForLoop(ForLoopLoc::Head),
1371+
orig_head_span,
1372+
None,
1373+
);
13661374
head.span = desugared_span;
13671375

13681376
let iter = Ident::with_dummy_span(sym::iter);
@@ -1457,10 +1465,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
14571465
// `mut iter => { ... }`
14581466
let iter_arm = self.arm(iter_pat, loop_expr);
14591467

1468+
let into_iter_span = self.mark_span_with_reason(
1469+
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
1470+
orig_head_span,
1471+
None,
1472+
);
1473+
14601474
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14611475
let into_iter_expr = {
14621476
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
1463-
self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
1477+
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
14641478
};
14651479

14661480
let match_expr = self.arena.alloc(self.expr_match(

src/librustc_infer/infer/error_reporting/need_type_info.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
455455
let msg = if let Some(simple_ident) = pattern.simple_ident() {
456456
match pattern.span.desugaring_kind() {
457457
None => format!("consider giving `{}` {}", simple_ident, suffix),
458-
Some(DesugaringKind::ForLoop) => {
458+
Some(DesugaringKind::ForLoop(_)) => {
459459
"the element type for this iterator is not specified".to_string()
460460
}
461461
_ => format!("this needs {}", suffix),

src/librustc_metadata/rmeta/decoder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1317,13 +1317,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
13171317
}
13181318
}
13191319

1320-
fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Symbol] {
1320+
fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
13211321
let param_names = match self.kind(id) {
13221322
EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
13231323
EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
13241324
_ => Lazy::empty(),
13251325
};
1326-
tcx.arena.alloc_from_iter(param_names.decode(self))
1326+
tcx.arena.alloc_from_iter(param_names.decode((self, tcx)))
13271327
}
13281328

13291329
fn exported_symbols(

src/librustc_metadata/rmeta/encoder.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
3030
use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder};
3131
use rustc_session::config::CrateType;
3232
use rustc_span::source_map::Spanned;
33-
use rustc_span::symbol::{kw, sym, Ident, Symbol};
33+
use rustc_span::symbol::{sym, Ident, Symbol};
3434
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
3535
use rustc_target::abi::VariantIdx;
3636
use std::hash::Hash;
@@ -997,18 +997,12 @@ impl EncodeContext<'tcx> {
997997
}
998998
}
999999

1000-
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Symbol]> {
1001-
self.tcx.dep_graph.with_ignore(|| {
1002-
let body = self.tcx.hir().body(body_id);
1003-
self.lazy(body.params.iter().map(|arg| match arg.pat.kind {
1004-
hir::PatKind::Binding(_, _, ident, _) => ident.name,
1005-
_ => kw::Invalid,
1006-
}))
1007-
})
1000+
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
1001+
self.tcx.dep_graph.with_ignore(|| self.lazy(self.tcx.hir().body_param_names(body_id)))
10081002
}
10091003

1010-
fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Symbol]> {
1011-
self.lazy(param_names.iter().map(|ident| ident.name))
1004+
fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Ident]> {
1005+
self.lazy(param_names.iter())
10121006
}
10131007

10141008
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {

src/librustc_metadata/rmeta/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_serialize::opaque::Encoder;
1919
use rustc_session::config::SymbolManglingVersion;
2020
use rustc_session::CrateDisambiguator;
2121
use rustc_span::edition::Edition;
22-
use rustc_span::symbol::Symbol;
22+
use rustc_span::symbol::{Ident, Symbol};
2323
use rustc_span::{self, Span};
2424
use rustc_target::spec::{PanicStrategy, TargetTriple};
2525

@@ -327,7 +327,7 @@ struct ModData {
327327
struct FnData {
328328
asyncness: hir::IsAsync,
329329
constness: hir::Constness,
330-
param_names: Lazy<[Symbol]>,
330+
param_names: Lazy<[Ident]>,
331331
}
332332

333333
#[derive(RustcEncodable, RustcDecodable)]

src/librustc_middle/hir/map/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_hir::*;
1414
use rustc_index::vec::IndexVec;
1515
use rustc_span::hygiene::MacroKind;
1616
use rustc_span::source_map::Spanned;
17-
use rustc_span::symbol::{kw, Symbol};
17+
use rustc_span::symbol::{kw, Ident, Symbol};
1818
use rustc_span::Span;
1919
use rustc_target::spec::abi::Abi;
2020

@@ -375,6 +375,13 @@ impl<'hir> Map<'hir> {
375375
})
376376
}
377377

378+
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
379+
self.body(id).params.iter().map(|arg| match arg.pat.kind {
380+
PatKind::Binding(_, _, ident, _) => ident,
381+
_ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
382+
})
383+
}
384+
378385
/// Returns the `BodyOwnerKind` of this `LocalDefId`.
379386
///
380387
/// Panics if `LocalDefId` does not have an associated body.

src/librustc_middle/hir/mod.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
1212
use rustc_data_structures::fx::FxHashMap;
1313
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1414
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
15-
use rustc_hir::Body;
16-
use rustc_hir::HirId;
17-
use rustc_hir::ItemLocalId;
18-
use rustc_hir::Node;
15+
use rustc_hir::*;
1916
use rustc_index::vec::IndexVec;
2017

2118
pub struct Owner<'tcx> {
@@ -79,5 +76,20 @@ pub fn provide(providers: &mut Providers<'_>) {
7976
};
8077
providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
8178
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
79+
providers.fn_arg_names = |tcx, id| {
80+
let hir = tcx.hir();
81+
let hir_id = hir.as_local_hir_id(id.expect_local());
82+
if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
83+
tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
84+
} else if let Node::TraitItem(&TraitItem {
85+
kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
86+
..
87+
}) = hir.get(hir_id)
88+
{
89+
tcx.arena.alloc_slice(idents)
90+
} else {
91+
span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
92+
}
93+
};
8294
map::provide(providers);
8395
}

src/librustc_middle/lint.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ pub fn struct_lint_level<'s, 'd>(
339339
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
340340
let expn_data = span.ctxt().outer_expn_data();
341341
match expn_data.kind {
342-
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
342+
ExpnKind::Root
343+
| ExpnKind::Desugaring(DesugaringKind::ForLoop(_))
344+
| ExpnKind::Desugaring(DesugaringKind::Operator) => false,
343345
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
344346
ExpnKind::Macro(MacroKind::Bang, _) => {
345347
// Dummy span for the `def_site` means it's an external macro.

src/librustc_middle/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ rustc_queries! {
706706
}
707707

708708
Other {
709-
query fn_arg_names(def_id: DefId) -> &'tcx [Symbol] {
709+
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
710710
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
711711
}
712712
/// Gets the rendered value of the specified constant or associated constant.

src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs

+65-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use crate::borrow_check::{
2424
};
2525

2626
use super::{
27-
explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
27+
explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
28+
RegionNameSource, UseSpans,
2829
};
2930

3031
#[derive(Debug)]
@@ -150,13 +151,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
150151
format!("value moved{} here, in previous iteration of loop", move_msg),
151152
);
152153
} else {
153-
err.span_label(move_span, format!("value moved{} here", move_msg));
154-
move_spans.var_span_label(
155-
&mut err,
156-
format!("variable moved due to use{}", move_spans.describe()),
157-
);
154+
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
155+
move_spans
156+
{
157+
let place_name = self
158+
.describe_place(moved_place.as_ref())
159+
.map(|n| format!("`{}`", n))
160+
.unwrap_or_else(|| "value".to_owned());
161+
match kind {
162+
FnSelfUseKind::FnOnceCall => {
163+
err.span_label(
164+
fn_call_span,
165+
&format!("{} moved due to this call", place_name),
166+
);
167+
err.span_note(
168+
var_span,
169+
"this value implements `FnOnce`, which causes it to be moved when called",
170+
);
171+
}
172+
FnSelfUseKind::Operator { self_arg } => {
173+
err.span_label(
174+
fn_call_span,
175+
&format!("{} moved due to usage in operator", place_name),
176+
);
177+
if self.fn_self_span_reported.insert(fn_span) {
178+
err.span_note(
179+
self_arg.span,
180+
"calling this operator moves the left-hand side",
181+
);
182+
}
183+
}
184+
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
185+
if implicit_into_iter {
186+
err.span_label(
187+
fn_call_span,
188+
&format!(
189+
"{} moved due to this implicit call to `.into_iter()`",
190+
place_name
191+
),
192+
);
193+
} else {
194+
err.span_label(
195+
fn_call_span,
196+
&format!("{} moved due to this method call", place_name),
197+
);
198+
}
199+
// Avoid pointing to the same function in multiple different
200+
// error messages
201+
if self.fn_self_span_reported.insert(self_arg.span) {
202+
err.span_note(
203+
self_arg.span,
204+
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
205+
);
206+
}
207+
}
208+
}
209+
} else {
210+
err.span_label(move_span, format!("value moved{} here", move_msg));
211+
move_spans.var_span_label(
212+
&mut err,
213+
format!("variable moved due to use{}", move_spans.describe()),
214+
);
215+
}
158216
}
159-
if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
217+
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
160218
let sess = self.infcx.tcx.sess;
161219
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
162220
err.span_suggestion(

src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
509509
// Used in a closure.
510510
(LaterUseKind::ClosureCapture, var_span)
511511
}
512-
UseSpans::OtherUse(span) => {
512+
UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => {
513513
let block = &self.body.basic_blocks()[location.block];
514514

515515
let kind = if let Some(&Statement {

0 commit comments

Comments
 (0)