Skip to content

Commit cad7d24

Browse files
committed
auto merge of #12733 : edwardw/rust/rw-liveness, r=nikomatsakis
- Repurposes `MoveData.assignee_ids` to mean only `=` but not `+=`, so that borrowck effectively classifies all expressions into assignees, uses or both. - Removes two `span_err` in liveness analysis, which are now borrowck's responsibilities. Closes #12527.
2 parents d75a6ab + abfde39 commit cad7d24

27 files changed

+119
-90
lines changed

Diff for: src/librustc/middle/borrowck/gather_loans/gather_moves.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,22 @@ pub fn gather_assignment(bccx: &BorrowckCtxt,
9494
assignee_loan_path,
9595
assignment_id,
9696
assignment_span,
97-
assignee_id);
97+
assignee_id,
98+
false);
99+
}
100+
101+
pub fn gather_move_and_assignment(bccx: &BorrowckCtxt,
102+
move_data: &MoveData,
103+
assignment_id: ast::NodeId,
104+
assignment_span: Span,
105+
assignee_loan_path: @LoanPath,
106+
assignee_id: ast::NodeId) {
107+
move_data.add_assignment(bccx.tcx,
108+
assignee_loan_path,
109+
assignment_id,
110+
assignment_span,
111+
assignee_id,
112+
true);
98113
}
99114

100115
fn check_is_legal_to_move_from(bccx: &BorrowckCtxt,

Diff for: src/librustc/middle/borrowck/gather_loans/mod.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -214,20 +214,19 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
214214
visit::walk_expr(this, ex, ());
215215
}
216216

217-
ast::ExprAssign(l, _) | ast::ExprAssignOp(_, l, _) => {
218-
let l_cmt = this.bccx.cat_expr(l);
219-
match opt_loan_path(l_cmt) {
220-
Some(l_lp) => {
221-
gather_moves::gather_assignment(this.bccx, &this.move_data,
222-
ex.id, ex.span,
223-
l_lp, l.id);
224-
}
225-
None => {
226-
// This can occur with e.g. `*foo() = 5`. In such
227-
// cases, there is no need to check for conflicts
228-
// with moves etc, just ignore.
229-
}
230-
}
217+
ast::ExprAssign(l, _) => {
218+
with_assignee_loan_path(
219+
this.bccx, l,
220+
|lp| gather_moves::gather_assignment(this.bccx, &this.move_data,
221+
ex.id, ex.span, lp, l.id));
222+
visit::walk_expr(this, ex, ());
223+
}
224+
225+
ast::ExprAssignOp(_, l, _) => {
226+
with_assignee_loan_path(
227+
this.bccx, l,
228+
|lp| gather_moves::gather_move_and_assignment(this.bccx, &this.move_data,
229+
ex.id, ex.span, lp, l.id));
231230
visit::walk_expr(this, ex, ());
232231
}
233232

@@ -288,17 +287,10 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
288287

289288
ast::ExprInlineAsm(ref ia) => {
290289
for &(_, out) in ia.outputs.iter() {
291-
let out_cmt = this.bccx.cat_expr(out);
292-
match opt_loan_path(out_cmt) {
293-
Some(out_lp) => {
294-
gather_moves::gather_assignment(this.bccx, &this.move_data,
295-
ex.id, ex.span,
296-
out_lp, out.id);
297-
}
298-
None => {
299-
// See the comment for ExprAssign.
300-
}
301-
}
290+
with_assignee_loan_path(
291+
this.bccx, out,
292+
|lp| gather_moves::gather_assignment(this.bccx, &this.move_data,
293+
ex.id, ex.span, lp, out.id));
302294
}
303295
visit::walk_expr(this, ex, ());
304296
}
@@ -309,6 +301,18 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
309301
}
310302
}
311303

304+
fn with_assignee_loan_path(bccx: &BorrowckCtxt, expr: &ast::Expr, op: |@LoanPath|) {
305+
let cmt = bccx.cat_expr(expr);
306+
match opt_loan_path(cmt) {
307+
Some(lp) => op(lp),
308+
None => {
309+
// This can occur with e.g. `*foo() = 5`. In such
310+
// cases, there is no need to check for conflicts
311+
// with moves etc, just ignore.
312+
}
313+
}
314+
}
315+
312316
impl<'a> GatherLoanCtxt<'a> {
313317
pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
314318

Diff for: src/librustc/middle/borrowck/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ impl BorrowckCtxt {
535535
move_data::Declared => {
536536
self.tcx.sess.span_err(
537537
use_span,
538-
format!("{} of possibly uninitialized value: `{}`",
538+
format!("{} of possibly uninitialized variable: `{}`",
539539
verb,
540540
self.loan_path_to_str(lp)));
541541
}

Diff for: src/librustc/middle/borrowck/move_data.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,25 @@ use util::ppaux::Repr;
3333

3434
pub struct MoveData {
3535
/// Move paths. See section "Move paths" in `doc.rs`.
36-
paths: RefCell<Vec<MovePath> >,
36+
paths: RefCell<Vec<MovePath>>,
3737

3838
/// Cache of loan path to move path index, for easy lookup.
3939
path_map: RefCell<HashMap<@LoanPath, MovePathIndex>>,
4040

4141
/// Each move or uninitialized variable gets an entry here.
42-
moves: RefCell<Vec<Move> >,
42+
moves: RefCell<Vec<Move>>,
4343

4444
/// Assignments to a variable, like `x = foo`. These are assigned
4545
/// bits for dataflow, since we must track them to ensure that
4646
/// immutable variables are assigned at most once along each path.
47-
var_assignments: RefCell<Vec<Assignment> >,
47+
var_assignments: RefCell<Vec<Assignment>>,
4848

4949
/// Assignments to a path, like `x.f = foo`. These are not
5050
/// assigned dataflow bits, but we track them because they still
5151
/// kill move bits.
52-
path_assignments: RefCell<Vec<Assignment> >,
52+
path_assignments: RefCell<Vec<Assignment>>,
53+
54+
/// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
5355
assignee_ids: RefCell<HashSet<ast::NodeId>>,
5456
}
5557

@@ -392,7 +394,8 @@ impl MoveData {
392394
lp: @LoanPath,
393395
assign_id: ast::NodeId,
394396
span: Span,
395-
assignee_id: ast::NodeId) {
397+
assignee_id: ast::NodeId,
398+
is_also_move: bool) {
396399
/*!
397400
* Adds a new record for an assignment to `lp` that occurs at
398401
* location `id` with the given `span`.
@@ -403,7 +406,7 @@ impl MoveData {
403406

404407
let path_index = self.move_path(tcx, lp);
405408

406-
{
409+
if !is_also_move {
407410
let mut assignee_ids = self.assignee_ids.borrow_mut();
408411
assignee_ids.get().insert(assignee_id);
409412
}

Diff for: src/librustc/middle/liveness.rs

+8-54
Original file line numberDiff line numberDiff line change
@@ -1468,28 +1468,14 @@ impl Liveness {
14681468

14691469
fn check_local(this: &mut Liveness, local: &Local) {
14701470
match local.init {
1471-
Some(_) => {
1472-
this.warn_about_unused_or_dead_vars_in_pat(local.pat);
1473-
}
1474-
None => {
1475-
1476-
// No initializer: the variable might be unused; if not, it
1477-
// should not be live at this point.
1478-
1479-
debug!("check_local() with no initializer");
1480-
this.pat_bindings(local.pat, |ln, var, sp, id| {
1481-
if !this.warn_about_unused(sp, id, ln, var) {
1482-
match this.live_on_exit(ln, var) {
1483-
None => { /* not live: good */ }
1484-
Some(lnk) => {
1485-
this.report_illegal_read(
1486-
local.span, lnk, var,
1487-
PossiblyUninitializedVariable);
1488-
}
1489-
}
1490-
}
1491-
})
1492-
}
1471+
Some(_) => {
1472+
this.warn_about_unused_or_dead_vars_in_pat(local.pat);
1473+
},
1474+
None => {
1475+
this.pat_bindings(local.pat, |ln, var, sp, id| {
1476+
this.warn_about_unused(sp, id, ln, var);
1477+
})
1478+
}
14931479
}
14941480

14951481
visit::walk_local(this, local, ());
@@ -1644,38 +1630,6 @@ impl Liveness {
16441630
}
16451631
}
16461632

1647-
pub fn report_illegal_read(&self,
1648-
chk_span: Span,
1649-
lnk: LiveNodeKind,
1650-
var: Variable,
1651-
rk: ReadKind) {
1652-
let msg = match rk {
1653-
PossiblyUninitializedVariable => "possibly uninitialized \
1654-
variable",
1655-
PossiblyUninitializedField => "possibly uninitialized field",
1656-
MovedValue => "moved value",
1657-
PartiallyMovedValue => "partially moved value"
1658-
};
1659-
let name = self.ir.variable_name(var);
1660-
match lnk {
1661-
FreeVarNode(span) => {
1662-
self.tcx.sess.span_err(
1663-
span,
1664-
format!("capture of {}: `{}`", msg, name));
1665-
}
1666-
ExprNode(span) => {
1667-
self.tcx.sess.span_err(
1668-
span,
1669-
format!("use of {}: `{}`", msg, name));
1670-
}
1671-
ExitNode | VarDefNode(_) => {
1672-
self.tcx.sess.span_bug(
1673-
chk_span,
1674-
format!("illegal reader: {:?}", lnk));
1675-
}
1676-
}
1677-
}
1678-
16791633
pub fn should_warn(&self, var: Variable) -> Option<~str> {
16801634
let name = self.ir.variable_name(var);
16811635
if name.len() == 0 || name[0] == ('_' as u8) { None } else { Some(name) }

Diff for: src/test/compile-fail/asm-out-read-uninit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn foo(x: int) { info!("{}", x); }
1919
pub fn main() {
2020
let x: int;
2121
unsafe {
22-
asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized value: `x`
22+
asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized variable: `x`
2323
}
2424
foo(x);
2525
}

Diff for: src/test/compile-fail/liveness-block-unint.rs renamed to src/test/compile-fail/borrowck-block-unint.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
fn force(f: ||) { f(); }
1212
fn main() {
1313
let x: int;
14-
force(|| {
15-
info!("{}", x); //~ ERROR capture of possibly uninitialized variable: `x`
14+
force(|| { //~ ERROR capture of possibly uninitialized variable: `x`
15+
info!("{}", x);
1616
});
1717
}
File renamed without changes.

Diff for: src/test/compile-fail/borrowck-uninit-in-assignop.rs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2012-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+
// Tests that the use of uninitialized variable in assignment operator
12+
// expression is detected.
13+
14+
pub fn main() {
15+
let x: int;
16+
x += 1; //~ ERROR use of possibly uninitialized variable: `x`
17+
18+
let x: int;
19+
x -= 1; //~ ERROR use of possibly uninitialized variable: `x`
20+
21+
let x: int;
22+
x *= 1; //~ ERROR use of possibly uninitialized variable: `x`
23+
24+
let x: int;
25+
x /= 1; //~ ERROR use of possibly uninitialized variable: `x`
26+
27+
let x: int;
28+
x %= 1; //~ ERROR use of possibly uninitialized variable: `x`
29+
30+
let x: int;
31+
x ^= 1; //~ ERROR use of possibly uninitialized variable: `x`
32+
33+
let x: int;
34+
x &= 1; //~ ERROR use of possibly uninitialized variable: `x`
35+
36+
let x: int;
37+
x |= 1; //~ ERROR use of possibly uninitialized variable: `x`
38+
39+
let x: int;
40+
x <<= 1; //~ ERROR use of possibly uninitialized variable: `x`
41+
42+
let x: int;
43+
x >>= 1; //~ ERROR use of possibly uninitialized variable: `x`
44+
}
File renamed without changes.

Diff for: src/test/compile-fail/liveness-use-in-index-lvalue.rs renamed to src/test/compile-fail/borrowck-use-in-index-lvalue.rs

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
fn test() {
1212
let w: ~[int];
13+
w[5] = 0; //~ ERROR use of possibly uninitialized variable: `w`
14+
//~^ ERROR cannot assign to immutable vec content `w[..]`
15+
16+
let mut w: ~[int];
1317
w[5] = 0; //~ ERROR use of possibly uninitialized variable: `w`
1418
}
1519

File renamed without changes.

Diff for: src/test/compile-fail/liveness-unused.rs

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ fn f1b(x: &mut int) {
2323
#[allow(unused_variable)]
2424
fn f1c(x: int) {}
2525

26+
fn f1d() {
27+
let x: int;
28+
//~^ ERROR unused variable: `x`
29+
}
30+
2631
fn f2() {
2732
let x = 3;
2833
//~^ ERROR unused variable: `x`

0 commit comments

Comments
 (0)