Skip to content

Commit a9c3841

Browse files
committed
Fix handling of move closures -- since they have one fewer deref, we weren't properly adjusting the closure kind in that case.
1 parent e778ea4 commit a9c3841

6 files changed

+167
-34
lines changed

src/librustc_typeck/check/upvar.rs

+65-33
Original file line numberDiff line numberDiff line change
@@ -263,16 +263,29 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
263263
match guarantor.cat {
264264
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
265265
mc::cat_deref(_, _, mc::Implicit(..)) => {
266-
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
267-
debug!("adjust_upvar_borrow_kind_for_consume: \
268-
setting upvar_id={:?} to by value",
269-
upvar_id);
266+
match cmt.note {
267+
mc::NoteUpvarRef(upvar_id) => {
268+
debug!("adjust_upvar_borrow_kind_for_consume: \
269+
setting upvar_id={:?} to by value",
270+
upvar_id);
270271

271-
// to move out of an upvar, this must be a FnOnce closure
272-
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
272+
// to move out of an upvar, this must be a FnOnce closure
273+
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
273274

274-
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
275-
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
275+
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
276+
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
277+
}
278+
mc::NoteClosureEnv(upvar_id) => {
279+
// we get just a closureenv ref if this is a
280+
// `move` closure, or if the upvar has already
281+
// been inferred to by-value. In any case, we
282+
// must still adjust the kind of the closure
283+
// to be a FnOnce closure to permit moves out
284+
// of the environment.
285+
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
286+
}
287+
mc::NoteNone => {
288+
}
276289
}
277290
}
278291
_ => { }
@@ -297,15 +310,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
297310

298311
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
299312
mc::cat_deref(base, _, mc::Implicit(..)) => {
300-
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
301-
// if this is an implicit deref of an
302-
// upvar, then we need to modify the
303-
// borrow_kind of the upvar to make sure it
304-
// is inferred to mutable if necessary
305-
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
306-
let ub = &mut upvar_capture_map[upvar_id];
307-
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::MutBorrow);
308-
} else {
313+
if !self.try_adjust_upvar_deref(&cmt.note, ty::MutBorrow) {
309314
// assignment to deref of an `&mut`
310315
// borrowed pointer implies that the
311316
// pointer itself must be unique, but not
@@ -339,15 +344,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
339344

340345
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
341346
mc::cat_deref(base, _, mc::Implicit(..)) => {
342-
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
343-
// if this is an implicit deref of an
344-
// upvar, then we need to modify the
345-
// borrow_kind of the upvar to make sure it
346-
// is inferred to unique if necessary
347-
let mut ub = self.fcx.inh.upvar_capture_map.borrow_mut();
348-
let ub = &mut ub[upvar_id];
349-
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::UniqueImmBorrow);
350-
} else {
347+
if !self.try_adjust_upvar_deref(&cmt.note, ty::UniqueImmBorrow) {
351348
// for a borrowed pointer to be unique, its
352349
// base must be unique
353350
self.adjust_upvar_borrow_kind_for_unique(base);
@@ -363,6 +360,48 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
363360
}
364361
}
365362

363+
fn try_adjust_upvar_deref(&self,
364+
note: &mc::Note,
365+
borrow_kind: ty::BorrowKind)
366+
-> bool
367+
{
368+
assert!(match borrow_kind {
369+
ty::MutBorrow => true,
370+
ty::UniqueImmBorrow => true,
371+
372+
// imm borrows never require adjusting any kinds, so we don't wind up here
373+
ty::ImmBorrow => false,
374+
});
375+
376+
match *note {
377+
mc::NoteUpvarRef(upvar_id) => {
378+
// if this is an implicit deref of an
379+
// upvar, then we need to modify the
380+
// borrow_kind of the upvar to make sure it
381+
// is inferred to mutable if necessary
382+
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
383+
let ub = &mut upvar_capture_map[upvar_id];
384+
self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
385+
386+
// also need to be in an FnMut closure since this is not an ImmBorrow
387+
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
388+
389+
true
390+
}
391+
mc::NoteClosureEnv(upvar_id) => {
392+
// this kind of deref occurs in a `move` closure, or
393+
// for a by-value upvar; in either case, to mutate an
394+
// upvar, we need to be an FnMut closure
395+
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
396+
397+
true
398+
}
399+
mc::NoteNone => {
400+
false
401+
}
402+
}
403+
}
404+
366405
/// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind
367406
/// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed
368407
/// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by
@@ -374,13 +413,6 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
374413
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
375414
upvar_id, upvar_capture, kind);
376415

377-
match kind {
378-
ty::ImmBorrow => { }
379-
ty::UniqueImmBorrow | ty::MutBorrow => {
380-
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
381-
}
382-
}
383-
384416
match *upvar_capture {
385417
ty::UpvarCapture::ByValue => {
386418
// Upvar is already by-value, the strongest criteria.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2015 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+
// Test that we are able to infer a suitable kind for this closure
12+
// that is just called (`FnMut`).
13+
14+
fn main() {
15+
let mut counter = 0;
16+
let tick = move || counter += 1;
17+
tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 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+
// Test that we are able to infer a suitable kind for this closure
12+
// that is just called (`FnMut`).
13+
14+
use std::mem;
15+
16+
fn main() {
17+
let mut counter: Vec<i32> = Vec::new();
18+
let tick = move || mem::drop(counter);
19+
tick();
20+
tick(); //~ ERROR use of moved value: `tick`
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2015 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+
// Test that we are able to infer a suitable kind for this `move`
12+
// closure that is just called (`FnMut`).
13+
14+
fn main() {
15+
let mut counter = 0;
16+
17+
let v = {
18+
let mut tick = move || { counter += 1; counter };
19+
tick();
20+
tick()
21+
};
22+
23+
assert_eq!(counter, 0);
24+
assert_eq!(v, 2);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2015 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(unsafe_destructor)]
12+
13+
// Test that we are able to infer a suitable kind for this `move`
14+
// closure that is just called (`FnOnce`).
15+
16+
use std::mem;
17+
18+
struct DropMe<'a>(&'a mut i32);
19+
20+
#[unsafe_destructor]
21+
impl<'a> Drop for DropMe<'a> {
22+
fn drop(&mut self) {
23+
*self.0 += 1;
24+
}
25+
}
26+
27+
fn main() {
28+
let mut counter = 0;
29+
30+
{
31+
let drop_me = DropMe(&mut counter);
32+
let tick = move || mem::drop(drop_me);
33+
tick();
34+
}
35+
36+
assert_eq!(counter, 1);
37+
}

src/test/run-pass/unboxed-closures-infer-fnonce.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![feature(unsafe_destructor)]
1212

1313
// Test that we are able to infer a suitable kind for this closure
14-
// that is just called (`FnMut`).
14+
// that is just called (`FnOnce`).
1515

1616
use std::mem;
1717

0 commit comments

Comments
 (0)