Issue #2633: remove last_use entries that are subject to a loan

This commit is contained in:
Niko Matsakis 2012-06-17 16:16:41 -07:00
parent 3e2006a570
commit 982e1166b2
6 changed files with 38 additions and 4 deletions

View file

@ -203,7 +203,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
bind middle::tstate::ck::check_crate(ty_cx, crate)); bind middle::tstate::ck::check_crate(ty_cx, crate));
let (root_map, mutbl_map) = time( let (root_map, mutbl_map) = time(
time_passes, "borrow checking", time_passes, "borrow checking",
bind middle::borrowck::check_crate(ty_cx, method_map, crate)); bind middle::borrowck::check_crate(ty_cx, method_map,
last_use_map, crate));
time(time_passes, "kind checking", time(time_passes, "kind checking",
bind kind::check_crate(ty_cx, method_map, last_use_map, crate)); bind kind::check_crate(ty_cx, method_map, last_use_map, crate));
time(time_passes, "lint checking", time(time_passes, "lint checking",

View file

@ -170,9 +170,11 @@ export check_crate, root_map, mutbl_map;
fn check_crate(tcx: ty::ctxt, fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map, method_map: typeck::method_map,
last_use_map: liveness::last_use_map,
crate: @ast::crate) -> (root_map, mutbl_map) { crate: @ast::crate) -> (root_map, mutbl_map) {
let bccx = @{tcx: tcx, let bccx = @{tcx: tcx,
method_map: method_map, method_map: method_map,
last_use_map: last_use_map,
root_map: root_map(), root_map: root_map(),
mutbl_map: int_hash()}; mutbl_map: int_hash()};
@ -186,6 +188,7 @@ fn check_crate(tcx: ty::ctxt,
type borrowck_ctxt = @{tcx: ty::ctxt, type borrowck_ctxt = @{tcx: ty::ctxt,
method_map: typeck::method_map, method_map: typeck::method_map,
last_use_map: liveness::last_use_map,
root_map: root_map, root_map: root_map,
mutbl_map: mutbl_map}; mutbl_map: mutbl_map};

View file

@ -448,6 +448,23 @@ impl methods for check_loan_ctxt {
} }
} }
// Very subtle (#2633): liveness can mark options as last_use even
// when there is an outstanding loan. In that case, it is not
// safe to consider the use a last_use.
fn check_last_use(expr: @ast::expr) {
let cmt = self.bccx.cat_expr(expr);
let lp = alt cmt.lp {
none { ret; }
some(lp) { lp }
};
for self.walk_loans_of(cmt.id, lp) { |_loan|
#debug["Removing last use entry %? due to outstanding loan",
expr.id];
self.bccx.last_use_map.remove(expr.id);
ret;
}
}
fn check_call(expr: @ast::expr, fn check_call(expr: @ast::expr,
callee: option<@ast::expr>, callee: option<@ast::expr>,
callee_id: ast::node_id, callee_id: ast::node_id,
@ -531,6 +548,10 @@ fn check_loans_in_expr(expr: @ast::expr,
self.check_for_conflicting_loans(expr.id); self.check_for_conflicting_loans(expr.id);
alt expr.node { alt expr.node {
ast::expr_path(*) if self.bccx.last_use_map.contains_key(expr.id) {
self.check_last_use(expr);
}
ast::expr_swap(l, r) { ast::expr_swap(l, r) {
self.check_assignment(at_swap, l); self.check_assignment(at_swap, l);
self.check_assignment(at_swap, r); self.check_assignment(at_swap, r);

View file

@ -63,6 +63,9 @@ export last_use_map;
// the local/argument/etc that the path refers to. However, it also // the local/argument/etc that the path refers to. However, it also
// possible for the expr to be a closure, in which case the list is a // possible for the expr to be a closure, in which case the list is a
// list of closed over variables that can be moved into the closure. // list of closed over variables that can be moved into the closure.
//
// Very subtle (#2633): borrowck will remove entries from this table
// if it detects an outstanding loan (that is, the addr is taken).
type last_use_map = hashmap<node_id, @dvec<node_id>>; type last_use_map = hashmap<node_id, @dvec<node_id>>;
enum variable = uint; enum variable = uint;

View file

@ -0,0 +1,8 @@
fn a_val(&&x: ~int, +y: ~int) -> int {
*x + *y
}
fn main() {
let z = ~22;
a_val(z, z);
}

View file

@ -1,5 +1,3 @@
// Currently segfaults
// xfail-test
class cat { class cat {
let mut meow: fn@(); let mut meow: fn@();
new() { self.meow = fn@() { #error("meow"); };} new() { self.meow = fn@() { #error("meow"); };}
@ -15,4 +13,4 @@ fn nyan(kitty: cat, _kitty_info: kitty_info) {
fn main() { fn main() {
let mut kitty = cat(); let mut kitty = cat();
nyan(kitty, {kitty: kitty}); nyan(kitty, {kitty: kitty});
} }