Skip to content

Commit 56232c6

Browse files
committed
Improved how upvars are detected when presenting errors using prefixes.
1 parent 0e5bda1 commit 56232c6

File tree

5 files changed

+55
-27
lines changed

5 files changed

+55
-27
lines changed

src/librustc/mir/tcx.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -151,25 +151,10 @@ impl<'tcx> Place<'tcx> {
151151
}
152152
},
153153
_ => None,
154-
},
154+
}
155155
_ => None,
156156
}
157157
}
158-
159-
/// Strip the deref projections from a `Place`. For example, given `(*(*((*_1).0: &&T)))`, this
160-
/// will return `((*_1).0)`. Once stripped of any deref projections, places can then be
161-
/// checked as upvar field projections using `is_upvar_field_projection`.
162-
pub fn strip_deref_projections(&self) -> &Place<'tcx> {
163-
let mut current = self;
164-
while let Place::Projection(ref proj) = current {
165-
if let ProjectionElem::Deref = proj.elem {
166-
current = &proj.base;
167-
} else {
168-
break;
169-
}
170-
}
171-
current
172-
}
173158
}
174159

175160
pub enum RvalueInitializationState {

src/librustc_mir/borrow_check/move_errors.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_data_structures::indexed_vec::Idx;
1616
use syntax_pos::Span;
1717

1818
use borrow_check::MirBorrowckCtxt;
19+
use borrow_check::prefixes::PrefixSet;
1920
use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind};
2021
use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
2122
use util::borrowck_errors::{BorrowckErrors, Origin};
@@ -254,15 +255,16 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
254255
// borrow to provide feedback about why this
255256
// was a move rather than a copy.
256257
let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
258+
let is_upvar_field_projection =
259+
self.prefixes(&original_path, PrefixSet::All)
260+
.any(|p| p.is_upvar_field_projection(self.mir, &self.tcx)
261+
.is_some());
257262
match ty.sty {
258263
ty::TyArray(..) | ty::TySlice(..) => self
259264
.tcx
260265
.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
261266
ty::TyClosure(def_id, closure_substs)
262-
if !self.mir.upvar_decls.is_empty() &&
263-
original_path.strip_deref_projections()
264-
.is_upvar_field_projection(self.mir, &self.tcx)
265-
.is_some()
267+
if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection
266268
=> {
267269
let closure_kind_ty =
268270
closure_substs.closure_kind_ty(def_id, self.tcx);
@@ -286,13 +288,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
286288
let mut diag = self.tcx.cannot_move_out_of(
287289
span, place_description, origin);
288290

289-
if let Some(field) = original_path.is_upvar_field_projection(
290-
self.mir, &self.tcx) {
291-
let upvar_decl = &self.mir.upvar_decls[field.index()];
292-
let upvar_hir_id = upvar_decl.var_hir_id.assert_crate_local();
293-
let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id);
294-
let upvar_span = self.tcx.hir.span(upvar_node_id);
295-
diag.span_label(upvar_span, "captured outer variable");
291+
for prefix in self.prefixes(&original_path, PrefixSet::All) {
292+
if let Some(field) = prefix.is_upvar_field_projection(
293+
self.mir, &self.tcx) {
294+
let upvar_decl = &self.mir.upvar_decls[field.index()];
295+
let upvar_hir_id =
296+
upvar_decl.var_hir_id.assert_crate_local();
297+
let upvar_node_id =
298+
self.tcx.hir.hir_to_node_id(upvar_hir_id);
299+
let upvar_span = self.tcx.hir.span(upvar_node_id);
300+
diag.span_label(upvar_span, "captured outer variable");
301+
break;
302+
}
296303
}
297304

298305
diag

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

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0507]: cannot move out of captured variable in an `FnMut` closure
22
--> $DIR/issue-4335.rs:16:20
33
|
4+
LL | fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> {
5+
| - captured outer variable
46
LL | id(Box::new(|| *v))
57
| ^^ cannot move out of captured variable in an `FnMut` closure
68

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(nll)]
12+
13+
fn expect_fn<F>(f: F) where F : Fn() {
14+
f();
15+
}
16+
17+
fn main() {
18+
{
19+
let x = (vec![22], vec![44]);
20+
expect_fn(|| drop(x.0));
21+
//~^ ERROR cannot move out of captured variable in an `Fn` closure [E0507]
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0507]: cannot move out of captured variable in an `Fn` closure
2+
--> $DIR/issue-52663-span-decl-captured-variable.rs:20:26
3+
|
4+
LL | let x = (vec![22], vec![44]);
5+
| - captured outer variable
6+
LL | expect_fn(|| drop(x.0));
7+
| ^^^ cannot move out of captured variable in an `Fn` closure
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0507`.

0 commit comments

Comments
 (0)