Skip to content

Commit aeca042

Browse files
committed
Auto merge of #52359 - matthewjasper:combine-move-error-reporting, r=pnkfelix
[NLL] Small move error reporting improvements * Use a MirBorrowckContext when reporting errors to be more uniform with other error reporting * Add a special message for the case of trying to move from capture variables in `Fn` and `FnMut` closures. part of #51028
2 parents 3d51086 + d34924d commit aeca042

12 files changed

+101
-88
lines changed

src/librustc_mir/borrow_check/mod.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use std::rc::Rc;
3434
use syntax_pos::Span;
3535

3636
use dataflow::indexes::BorrowIndex;
37-
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
37+
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError, MovePathIndex};
3838
use dataflow::Borrows;
3939
use dataflow::DataflowResultsConsumer;
4040
use dataflow::FlowAtLocation;
@@ -148,13 +148,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
148148
let mir = &mir; // no further changes
149149
let location_table = &LocationTable::new(mir);
150150

151-
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
152-
Ok(move_data) => move_data,
153-
Err((move_data, move_errors)) => {
154-
move_errors::report_move_errors(&mir, tcx, move_errors, &move_data);
155-
move_data
156-
}
157-
};
151+
let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<MoveError<'tcx>>>) =
152+
match MoveData::gather_moves(mir, tcx) {
153+
Ok(move_data) => (move_data, None),
154+
Err((move_data, move_errors)) => (move_data, Some(move_errors)),
155+
};
158156

159157
let mdpe = MoveDataParamEnv {
160158
move_data: move_data,
@@ -271,6 +269,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
271269
polonius_output,
272270
);
273271

272+
if let Some(errors) = move_errors {
273+
mbcx.report_move_errors(errors);
274+
}
274275
mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
275276

276277
// For each non-user used mutable variable, check if it's been assigned from
@@ -1975,7 +1976,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
19751976
ProjectionElem::Field(field, _ty) => {
19761977
let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
19771978

1978-
if base_ty.is_closure() || base_ty.is_generator() {
1979+
if base_ty.is_closure() || base_ty.is_generator() {
19791980
Some(field)
19801981
} else {
19811982
None

src/librustc_mir/borrow_check/move_errors.rs

+50-39
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,16 @@
1010

1111
use rustc::hir;
1212
use rustc::mir::*;
13-
use rustc::ty::{self, TyCtxt};
13+
use rustc::ty;
14+
use rustc_data_structures::indexed_vec::Idx;
1415
use rustc_errors::DiagnosticBuilder;
1516
use syntax_pos::Span;
1617

17-
use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind, MoveData};
18+
use borrow_check::MirBorrowckCtxt;
19+
use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind};
1820
use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
1921
use util::borrowck_errors::{BorrowckErrors, Origin};
2022

21-
pub(crate) fn report_move_errors<'gcx, 'tcx>(
22-
mir: &Mir<'tcx>,
23-
tcx: TyCtxt<'_, 'gcx, 'tcx>,
24-
move_errors: Vec<MoveError<'tcx>>,
25-
move_data: &MoveData<'tcx>,
26-
) {
27-
MoveErrorCtxt {
28-
mir,
29-
tcx,
30-
move_data,
31-
}.report_errors(move_errors);
32-
}
33-
34-
#[derive(Copy, Clone)]
35-
struct MoveErrorCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> {
36-
mir: &'a Mir<'tcx>,
37-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
38-
move_data: &'a MoveData<'tcx>,
39-
}
40-
4123
// Often when desugaring a pattern match we may have many individual moves in
4224
// MIR that are all part of one operation from the user's point-of-view. For
4325
// example:
@@ -76,15 +58,15 @@ enum GroupedMoveError<'tcx> {
7658
},
7759
}
7860

79-
impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
80-
fn report_errors(self, move_errors: Vec<MoveError<'tcx>>) {
61+
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
62+
pub(crate) fn report_move_errors(&self, move_errors: Vec<MoveError<'tcx>>) {
8163
let grouped_errors = self.group_move_errors(move_errors);
8264
for error in grouped_errors {
8365
self.report(error);
8466
}
8567
}
8668

87-
fn group_move_errors(self, errors: Vec<MoveError<'tcx>>) -> Vec<GroupedMoveError<'tcx>> {
69+
fn group_move_errors(&self, errors: Vec<MoveError<'tcx>>) -> Vec<GroupedMoveError<'tcx>> {
8870
let mut grouped_errors = Vec::new();
8971
for error in errors {
9072
self.append_to_grouped_errors(&mut grouped_errors, error);
@@ -93,7 +75,7 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
9375
}
9476

9577
fn append_to_grouped_errors(
96-
self,
78+
&self,
9779
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
9880
error: MoveError<'tcx>,
9981
) {
@@ -114,19 +96,19 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
11496
.map(|stmt| &stmt.kind)
11597
{
11698
let local_decl = &self.mir.local_decls[*local];
99+
// opt_match_place is the
100+
// match_span is the span of the expression being matched on
101+
// match *x.y { ... } match_place is Some(*x.y)
102+
// ^^^^ match_span is the span of *x.y
103+
//
104+
// opt_match_place is None for let [mut] x = ... statements,
105+
// whether or not the right-hand side is a place expression
117106
if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
118107
opt_match_place: Some((ref opt_match_place, match_span)),
119108
binding_mode: _,
120109
opt_ty_info: _,
121110
}))) = local_decl.is_user_variable
122111
{
123-
// opt_match_place is the
124-
// match_span is the span of the expression being matched on
125-
// match *x.y { ... } match_place is Some(*x.y)
126-
// ^^^^ match_span is the span of *x.y
127-
// opt_match_place is None for let [mut] x = ... statements,
128-
// whether or not the right-hand side is a place expression
129-
130112
// HACK use scopes to determine if this assignment is
131113
// the initialization of a variable.
132114
// FIXME(matthewjasper) This would probably be more
@@ -145,8 +127,8 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
145127
opt_match_place,
146128
match_span,
147129
);
130+
return;
148131
}
149-
return;
150132
}
151133
}
152134
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
@@ -158,7 +140,7 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
158140
}
159141

160142
fn append_binding_error(
161-
self,
143+
&self,
162144
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
163145
kind: IllegalMoveOriginKind<'tcx>,
164146
move_from: &Place<'tcx>,
@@ -236,7 +218,7 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
236218
};
237219
}
238220

239-
fn report(self, error: GroupedMoveError<'tcx>) {
221+
fn report(&self, error: GroupedMoveError<'tcx>) {
240222
let (mut err, err_span) = {
241223
let (span, kind): (Span, &IllegalMoveOriginKind) = match error {
242224
GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. }
@@ -249,14 +231,43 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
249231
IllegalMoveOriginKind::Static => {
250232
self.tcx.cannot_move_out_of(span, "static item", origin)
251233
}
252-
IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
234+
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
253235
// Inspect the type of the content behind the
254236
// borrow to provide feedback about why this
255237
// was a move rather than a copy.
238+
let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
256239
match ty.sty {
257240
ty::TyArray(..) | ty::TySlice(..) => self
258241
.tcx
259242
.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
243+
ty::TyClosure(def_id, closure_substs)
244+
if !self.mir.upvar_decls.is_empty()
245+
&& {
246+
match place {
247+
Place::Projection(ref proj) => {
248+
proj.base == Place::Local(Local::new(1))
249+
}
250+
Place::Local(_) | Place::Static(_) => unreachable!(),
251+
}
252+
} =>
253+
{
254+
let closure_kind_ty =
255+
closure_substs.closure_kind_ty(def_id, self.tcx);
256+
let closure_kind = closure_kind_ty.to_opt_closure_kind();
257+
let place_description = match closure_kind {
258+
Some(ty::ClosureKind::Fn) => {
259+
"captured variable in an `Fn` closure"
260+
}
261+
Some(ty::ClosureKind::FnMut) => {
262+
"captured variable in an `FnMut` closure"
263+
}
264+
Some(ty::ClosureKind::FnOnce) => {
265+
bug!("closure kind does not match first argument type")
266+
}
267+
None => bug!("closure kind not inferred by borrowck"),
268+
};
269+
self.tcx.cannot_move_out_of(span, place_description, origin)
270+
}
260271
_ => self
261272
.tcx
262273
.cannot_move_out_of(span, "borrowed content", origin),
@@ -279,7 +290,7 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
279290
}
280291

281292
fn add_move_hints(
282-
self,
293+
&self,
283294
error: GroupedMoveError<'tcx>,
284295
err: &mut DiagnosticBuilder<'a>,
285296
span: Span,
@@ -365,7 +376,7 @@ impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
365376
}
366377
}
367378

368-
fn suitable_to_remove_deref(self, proj: &PlaceProjection<'tcx>, snippet: &str) -> bool {
379+
fn suitable_to_remove_deref(&self, proj: &PlaceProjection<'tcx>, snippet: &str) -> bool {
369380
let is_shared_ref = |ty: ty::Ty| match ty.sty {
370381
ty::TypeVariants::TyRef(.., hir::Mutability::MutImmutable) => true,
371382
_ => false,

src/librustc_mir/dataflow/move_paths/builder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
132132
let mir = self.builder.mir;
133133
let tcx = self.builder.tcx;
134134
let place_ty = proj.base.ty(mir, tcx).to_ty(tcx);
135-
match place_ty.sty {
135+
match place_ty.sty {
136136
ty::TyRef(..) | ty::TyRawPtr(..) =>
137137
return Err(MoveError::cannot_move_out_of(
138138
self.loc,
139-
BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })),
139+
BorrowedContent { target_place: place.clone() })),
140140
ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
141141
return Err(MoveError::cannot_move_out_of(self.loc,
142142
InteriorOfTypeWithDestructor {

src/librustc_mir/dataflow/move_paths/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,9 @@ pub(crate) enum IllegalMoveOriginKind<'tcx> {
282282

283283
/// Illegal move due to attempt to move from behind a reference.
284284
BorrowedContent {
285-
/// The content's type: if erroneous code was trying to move
286-
/// from `*x` where `x: &T`, then this will be `T`.
287-
target_ty: ty::Ty<'tcx>,
285+
/// The place the reference refers to: if erroneous code was trying to
286+
/// move from `(*x).f` this will be `*x`.
287+
target_place: Place<'tcx>,
288288
},
289289

290290
/// Illegal move due to attempt to move from field of an ADT that

src/test/ui/borrowck/borrowck-in-static.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0507]: cannot move out of borrowed content
1+
error[E0507]: cannot move out of captured variable in an `Fn` closure
22
--> $DIR/borrowck-in-static.rs:15:17
33
|
44
LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable
5-
| ^ cannot move out of borrowed content
5+
| ^ cannot move out of captured variable in an `Fn` closure
66

77
error: aborting due to previous error
88

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0507]: cannot move out of borrowed content
1+
error[E0507]: cannot move out of captured variable in an `Fn` closure
22
--> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9
33
|
44
LL | y.into_iter();
5-
| ^ cannot move out of borrowed content
5+
| ^ cannot move out of captured variable in an `Fn` closure
66

77
error: aborting due to previous error
88

src/test/ui/error-codes/E0161.nll.stderr

-16
This file was deleted.

src/test/ui/issue-20801.nll.stderr

+22-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
1-
error: internal compiler error: Accessing `(*_8)` with the kind `Write(Move)` shouldn't be possible
1+
error[E0507]: cannot move out of borrowed content
2+
--> $DIR/issue-20801.rs:36:22
3+
|
4+
LL | let a = unsafe { *mut_ref() };
5+
| ^^^^^^^^^^ cannot move out of borrowed content
6+
7+
error[E0507]: cannot move out of borrowed content
8+
--> $DIR/issue-20801.rs:39:22
9+
|
10+
LL | let b = unsafe { *imm_ref() };
11+
| ^^^^^^^^^^ cannot move out of borrowed content
12+
13+
error[E0507]: cannot move out of borrowed content
14+
--> $DIR/issue-20801.rs:42:22
15+
|
16+
LL | let c = unsafe { *mut_ptr() };
17+
| ^^^^^^^^^^ cannot move out of borrowed content
18+
19+
error[E0507]: cannot move out of borrowed content
220
--> $DIR/issue-20801.rs:45:22
321
|
422
LL | let d = unsafe { *const_ptr() };
5-
| ^^^^^^^^^^^^
23+
| ^^^^^^^^^^^^ cannot move out of borrowed content
624

7-
error: aborting due to previous error
25+
error: aborting due to 4 previous errors
826

27+
For more information about this error, try `rustc --explain E0507`.

src/test/ui/issue-20801.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-test currently ICEs when using NLL (#52416)
12-
1311
// We used to ICE when moving out of a `*mut T` or `*const T`.
1412

1513
struct T(u8);

src/test/ui/issue-30355.nll.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error[E0508]: cannot move out of type `[u8]`, a non-copy slice
2-
--> $DIR/issue-30355.rs:15:8
3-
|
4-
LL | &X(*Y)
5-
| ^^ cannot move out of here
6-
71
error[E0161]: cannot move a value of type X: the size of X cannot be statically determined
82
--> $DIR/issue-30355.rs:15:6
93
|
@@ -16,6 +10,12 @@ error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be stati
1610
LL | &X(*Y)
1711
| ^^
1812

13+
error[E0508]: cannot move out of type `[u8]`, a non-copy slice
14+
--> $DIR/issue-30355.rs:15:8
15+
|
16+
LL | &X(*Y)
17+
| ^^ cannot move out of here
18+
1919
error: aborting due to 3 previous errors
2020

2121
Some errors occurred: E0161, E0508.

src/test/ui/issue-4335.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0507]: cannot move out of borrowed content
1+
error[E0507]: cannot move out of captured variable in an `FnMut` closure
22
--> $DIR/issue-4335.rs:16:20
33
|
44
LL | id(Box::new(|| *v))
5-
| ^^ cannot move out of borrowed content
5+
| ^^ cannot move out of captured variable in an `FnMut` closure
66

77
error[E0597]: `v` does not live long enough
88
--> $DIR/issue-4335.rs:16:17

src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ LL | fn test4(f: &Test) {
2828
LL | f.f.call_mut(())
2929
| ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
3030

31-
error[E0507]: cannot move out of borrowed content
31+
error[E0507]: cannot move out of captured variable in an `FnMut` closure
3232
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
3333
|
3434
LL | foo(f);
35-
| ^ cannot move out of borrowed content
35+
| ^ cannot move out of captured variable in an `FnMut` closure
3636

3737
error[E0505]: cannot move out of `f` because it is borrowed
3838
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:65:16

0 commit comments

Comments
 (0)