Skip to content

Commit 61d7917

Browse files
committed
auto merge of #14318 : zwarich/rust/check-loans-refactor, r=nikomatsakis
I tried to split up the less mechanical changes into separate commits so they are easier to review. One thing I'm not quite sure of is whether `MoveReason` should just be replaced with `move_data::MoveKind`.
2 parents 3744940 + f1542a6 commit 61d7917

16 files changed

+723
-274
lines changed

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 248 additions & 233 deletions
Large diffs are not rendered by default.

src/librustc/middle/borrowck/gather_loans/gather_moves.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,15 @@ pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
4545
move_data: &MoveData,
4646
move_error_collector: &MoveErrorCollector,
4747
move_expr_id: ast::NodeId,
48-
cmt: mc::cmt) {
48+
cmt: mc::cmt,
49+
move_reason: euv::MoveReason) {
50+
let kind = match move_reason {
51+
euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
52+
euv::CaptureMove => Captured
53+
};
4954
let move_info = GatherMoveInfo {
5055
id: move_expr_id,
51-
kind: MoveExpr,
56+
kind: kind,
5257
cmt: cmt,
5358
span_path_opt: None,
5459
};

src/librustc/middle/borrowck/gather_loans/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,13 @@ impl<'a> euv::Delegate for GatherLoanCtxt<'a> {
7575
consume_id, cmt.repr(self.tcx()), mode);
7676

7777
match mode {
78-
euv::Copy => { return; }
79-
euv::Move => { }
78+
euv::Move(move_reason) => {
79+
gather_moves::gather_move_from_expr(
80+
self.bccx, &self.move_data, &self.move_error_collector,
81+
consume_id, cmt, move_reason);
82+
}
83+
euv::Copy => { }
8084
}
81-
82-
gather_moves::gather_move_from_expr(
83-
self.bccx, &self.move_data, &self.move_error_collector,
84-
consume_id, cmt);
8585
}
8686

8787
fn consume_pat(&mut self,
@@ -95,7 +95,7 @@ impl<'a> euv::Delegate for GatherLoanCtxt<'a> {
9595

9696
match mode {
9797
euv::Copy => { return; }
98-
euv::Move => { }
98+
euv::Move(_) => { }
9999
}
100100

101101
gather_moves::gather_move_from_pat(

src/librustc/middle/borrowck/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
142142
body);
143143

144144
check_loans::check_loans(this, &loan_dfcx, flowed_moves,
145-
all_loans.as_slice(), body);
145+
all_loans.as_slice(), decl, body);
146146

147147
visit::walk_fn(this, fk, decl, body, sp, ());
148148
}

src/librustc/middle/borrowck/move_data.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ pub struct MovePath {
115115
pub next_sibling: MovePathIndex,
116116
}
117117

118+
#[deriving(PartialEq)]
118119
pub enum MoveKind {
119120
Declared, // When declared, variables start out "moved".
120121
MoveExpr, // Expression or binding that moves a variable
@@ -356,7 +357,7 @@ impl MoveData {
356357
let path_index = self.move_path(tcx, lp.clone());
357358

358359
match mode {
359-
euv::JustWrite => {
360+
euv::Init | euv::JustWrite => {
360361
self.assignee_ids.borrow_mut().insert(assignee_id);
361362
}
362363
euv::WriteAndRead => { }
@@ -537,6 +538,28 @@ impl<'a> FlowedMoveData<'a> {
537538
})
538539
}
539540

541+
pub fn kind_of_move_of_path(&self,
542+
id: ast::NodeId,
543+
loan_path: &Rc<LoanPath>)
544+
-> Option<MoveKind> {
545+
//! Returns the kind of a move of `loan_path` by `id`, if one exists.
546+
547+
let mut ret = None;
548+
for loan_path_index in self.move_data.path_map.borrow().find(&*loan_path).iter() {
549+
self.dfcx_moves.each_gen_bit_frozen(id, |move_index| {
550+
let move = self.move_data.moves.borrow();
551+
let move = move.get(move_index);
552+
if move.path == **loan_path_index {
553+
ret = Some(move.kind);
554+
false
555+
} else {
556+
true
557+
}
558+
});
559+
}
560+
ret
561+
}
562+
540563
pub fn each_move_of(&self,
541564
id: ast::NodeId,
542565
loan_path: &Rc<LoanPath>,

src/librustc/middle/expr_use_visitor.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,20 @@ pub enum LoanCause {
8080

8181
#[deriving(PartialEq,Show)]
8282
pub enum ConsumeMode {
83-
Copy, // reference to x where x has a type that copies
84-
Move, // reference to x where x has a type that moves
83+
Copy, // reference to x where x has a type that copies
84+
Move(MoveReason), // reference to x where x has a type that moves
85+
}
86+
87+
#[deriving(PartialEq,Show)]
88+
pub enum MoveReason {
89+
DirectRefMove,
90+
PatBindingMove,
91+
CaptureMove,
8592
}
8693

8794
#[deriving(PartialEq,Show)]
8895
pub enum MutateMode {
96+
Init,
8997
JustWrite, // x = y
9098
WriteAndRead, // x += y
9199
}
@@ -160,7 +168,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
160168
consume_id: ast::NodeId,
161169
consume_span: Span,
162170
cmt: mc::cmt) {
163-
let mode = copy_or_move(self.tcx(), cmt.ty);
171+
let mode = copy_or_move(self.tcx(), cmt.ty, DirectRefMove);
164172
self.delegate.consume(consume_id, consume_span, cmt, mode);
165173
}
166174

@@ -712,7 +720,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
712720
let def = def_map.borrow().get_copy(&pat.id);
713721
match mc.cat_def(pat.id, pat.span, pat_ty, def) {
714722
Ok(binding_cmt) => {
715-
delegate.mutate(pat.id, pat.span, binding_cmt, JustWrite);
723+
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
716724
}
717725
Err(_) => { }
718726
}
@@ -728,7 +736,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
728736
r, bk, RefBinding);
729737
}
730738
ast::PatIdent(ast::BindByValue(_), _, _) => {
731-
let mode = copy_or_move(typer.tcx(), cmt_pat.ty);
739+
let mode = copy_or_move(typer.tcx(), cmt_pat.ty, PatBindingMove);
732740
delegate.consume_pat(pat, cmt_pat, mode);
733741
}
734742
_ => {
@@ -834,7 +842,8 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
834842
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
835843
closure_expr.span,
836844
freevar.def));
837-
self.delegate_consume(closure_expr.id, freevar.span, cmt_var);
845+
let mode = copy_or_move(self.tcx(), cmt_var.ty, CaptureMove);
846+
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
838847
}
839848
}
840849

@@ -851,7 +860,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
851860
}
852861
}
853862

854-
fn copy_or_move(tcx: &ty::ctxt, ty: ty::t) -> ConsumeMode {
855-
if ty::type_moves_by_default(tcx, ty) { Move } else { Copy }
863+
fn copy_or_move(tcx: &ty::ctxt, ty: ty::t, move_reason: MoveReason) -> ConsumeMode {
864+
if ty::type_moves_by_default(tcx, ty) { Move(move_reason) } else { Copy }
856865
}
857866

src/librustc/middle/mem_categorization.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,12 +390,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
390390
Some(adjustment) => {
391391
match *adjustment {
392392
ty::AutoObject(..) => {
393-
// Implicity casts a concrete object to trait object
394-
// so just patch up the type
393+
// Implicity cast a concrete object to trait object.
394+
// Result is an rvalue.
395395
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
396-
let mut expr_cmt = (*if_ok!(self.cat_expr_unadjusted(expr))).clone();
397-
expr_cmt.ty = expr_ty;
398-
Ok(Rc::new(expr_cmt))
396+
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
399397
}
400398

401399
ty::AutoAddEnv(..) => {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright 2014 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+
struct A { a: int, b: Box<int> }
12+
13+
fn borrow<T>(_: &T) { }
14+
15+
fn use_after_move() {
16+
let x = A { a: 1, b: box 2 };
17+
drop(x.b);
18+
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
19+
}
20+
21+
fn use_after_fu_move() {
22+
let x = A { a: 1, b: box 2 };
23+
let y = A { a: 3, .. x };
24+
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
25+
}
26+
27+
fn borrow_after_move() {
28+
let x = A { a: 1, b: box 2 };
29+
drop(x.b);
30+
borrow(&x.b); //~ ERROR use of moved value: `x.b`
31+
}
32+
33+
fn borrow_after_fu_move() {
34+
let x = A { a: 1, b: box 2 };
35+
let _y = A { a: 3, .. x };
36+
borrow(&x.b); //~ ERROR use of moved value: `x.b`
37+
}
38+
39+
fn move_after_borrow() {
40+
let x = A { a: 1, b: box 2 };
41+
let y = &x.b;
42+
drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
43+
borrow(&*y);
44+
}
45+
46+
fn fu_move_after_borrow() {
47+
let x = A { a: 1, b: box 2 };
48+
let y = &x.b;
49+
let _z = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
50+
borrow(&*y);
51+
}
52+
53+
fn mut_borrow_after_mut_borrow() {
54+
let mut x = A { a: 1, b: box 2 };
55+
let y = &mut x.a;
56+
let z = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time
57+
drop(*y);
58+
drop(*z);
59+
}
60+
61+
fn move_after_move() {
62+
let x = A { a: 1, b: box 2 };
63+
drop(x.b);
64+
drop(x.b); //~ ERROR use of moved value: `x.b`
65+
}
66+
67+
fn move_after_fu_move() {
68+
let x = A { a: 1, b: box 2 };
69+
let _y = A { a: 3, .. x };
70+
drop(x.b); //~ ERROR use of moved value: `x.b`
71+
}
72+
73+
fn fu_move_after_move() {
74+
let x = A { a: 1, b: box 2 };
75+
drop(x.b);
76+
let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b`
77+
}
78+
79+
fn fu_move_after_fu_move() {
80+
let x = A { a: 1, b: box 2 };
81+
let _y = A { a: 3, .. x };
82+
let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b`
83+
}
84+
85+
// The following functions aren't yet accepted, but they should be.
86+
87+
fn use_after_field_assign_after_uninit() {
88+
let mut x: A;
89+
x.a = 1;
90+
drop(x.a); //~ ERROR use of possibly uninitialized variable: `x.a`
91+
}
92+
93+
fn borrow_after_field_assign_after_uninit() {
94+
let mut x: A;
95+
x.a = 1;
96+
borrow(&x.a); //~ ERROR use of possibly uninitialized variable: `x.a`
97+
}
98+
99+
fn move_after_field_assign_after_uninit() {
100+
let mut x: A;
101+
x.b = box 1;
102+
drop(x.b); //~ ERROR use of possibly uninitialized variable: `x.b`
103+
}
104+
105+
fn main() {
106+
use_after_move();
107+
use_after_fu_move();
108+
109+
borrow_after_move();
110+
borrow_after_fu_move();
111+
move_after_borrow();
112+
fu_move_after_borrow();
113+
mut_borrow_after_mut_borrow();
114+
115+
move_after_move();
116+
move_after_fu_move();
117+
fu_move_after_move();
118+
fu_move_after_fu_move();
119+
120+
use_after_field_assign_after_uninit();
121+
borrow_after_field_assign_after_uninit();
122+
move_after_field_assign_after_uninit();
123+
}
124+

src/test/compile-fail/borrowck-init-in-fru.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ struct point {
1616

1717
fn main() {
1818
let mut origin: point;
19-
origin = point {x: 10,.. origin}; //~ ERROR use of possibly uninitialized variable: `origin`
19+
origin = point {x: 10,.. origin}; //~ ERROR use of possibly uninitialized variable: `origin.y`
2020
origin.clone();
2121
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2014 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+
use std::task;
12+
13+
fn borrow<T>(_: &T) { }
14+
15+
fn different_vars_after_borrows() {
16+
let x1 = box 1;
17+
let p1 = &x1;
18+
let x2 = box 2;
19+
let p2 = &x2;
20+
task::spawn(proc() {
21+
drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed
22+
drop(x2); //~ ERROR cannot move `x2` into closure because it is borrowed
23+
});
24+
borrow(&*p1);
25+
borrow(&*p2);
26+
}
27+
28+
fn different_vars_after_moves() {
29+
let x1 = box 1;
30+
drop(x1);
31+
let x2 = box 2;
32+
drop(x2);
33+
task::spawn(proc() {
34+
drop(x1); //~ ERROR capture of moved value: `x1`
35+
drop(x2); //~ ERROR capture of moved value: `x2`
36+
});
37+
}
38+
39+
fn same_var_after_borrow() {
40+
let x = box 1;
41+
let p = &x;
42+
task::spawn(proc() {
43+
drop(x); //~ ERROR cannot move `x` into closure because it is borrowed
44+
drop(x); //~ ERROR use of moved value: `x`
45+
});
46+
borrow(&*p);
47+
}
48+
49+
fn same_var_after_move() {
50+
let x = box 1;
51+
drop(x);
52+
task::spawn(proc() {
53+
drop(x); //~ ERROR capture of moved value: `x`
54+
drop(x); //~ ERROR use of moved value: `x`
55+
});
56+
}
57+
58+
fn main() {
59+
different_vars_after_borrows();
60+
different_vars_after_moves();
61+
same_var_after_borrow();
62+
same_var_after_move();
63+
}
64+

src/test/compile-fail/liveness-use-after-move.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ extern crate debug;
1313
fn main() {
1414
let x = box 5;
1515
let y = x;
16-
println!("{:?}", *x); //~ ERROR use of moved value: `x`
16+
println!("{:?}", *x); //~ ERROR use of partially moved value: `*x`
1717
y.clone();
1818
}

0 commit comments

Comments
 (0)