From 537d879dc1437744e375d58bcce14bc427d904a2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 Jun 2011 14:19:13 +0200 Subject: [PATCH] Properly handle lifetime of aliases in nested blocks There was a bug that would cause the alias analyser to allow you to invalidate an alias that was no longer directly referred to, even if another alias was rooted in it. It now properly tracks dependencies between live aliases. Required another case of copying values in map.rs. --- src/comp/middle/alias.rs | 59 ++++++++++++++++++++++++++++------------ src/lib/map.rs | 3 +- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index fa978ef53c03..bad328e028c0 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -20,6 +20,7 @@ type restrict = @rec(vec[def_num] root_vars, def_num block_defnum, vec[def_num] bindings, vec[ty::t] tys, + vec[uint] depends_on, mutable valid ok); type scope = vec[restrict]; @@ -182,6 +183,7 @@ fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, block_defnum=dnums.(0), bindings=dnums, tys=forbidden_tp, + depends_on=deps(sc, roots), mutable ok=valid)); } visit::visit_arm(a, new_sc, v); @@ -221,6 +223,7 @@ fn check_for_each(&ctx cx, &@ast::decl decl, &@ast::expr call, block_defnum=defnum, bindings=[defnum], tys=data.unsafe_ts, + depends_on=deps(sc, data.root_vars), mutable ok=valid); visit::visit_block(block, sc + [new_sc], v); } @@ -256,6 +259,7 @@ fn check_for(&ctx cx, &@ast::decl decl, &@ast::expr seq, block_defnum=defnum, bindings=[defnum], tys=unsafe, + depends_on=deps(sc, root_def), mutable ok=valid); visit::visit_block(block, sc + [new_sc], v); } @@ -274,24 +278,8 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign, r.ok = val_taken(ex.span, p); } } - } else if (r.ok != valid && vec::member(my_defnum, r.bindings)) { - fail_alias(cx, r.ok, p); - } - } -} - -fn fail_alias(&ctx cx, valid issue, &ast::path pt) { - auto base = " will invalidate alias " + ast::path_name(pt) + - ", which is still used"; - alt (issue) { - case (overwritten(?sp, ?wpt)) { - cx.tcx.sess.span_err - (sp, "overwriting " + ast::path_name(wpt) + base); - } - case (val_taken(?sp, ?vpt)) { - cx.tcx.sess.span_err - (sp, "taking the value of " + ast::path_name(vpt) + - base); + } else if (vec::member(my_defnum, r.bindings)) { + test_scope(cx, sc, r, p); } } } @@ -316,6 +304,41 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, } } +fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) { + auto prob = r.ok; + for (uint dep in r.depends_on) { + if (prob != valid) { break; } + prob = sc.(dep).ok; + } + if (prob != valid) { + auto msg = alt (prob) { + case (overwritten(?sp, ?wpt)) { + tup(sp, "overwriting " + ast::path_name(wpt)) + } + case (val_taken(?sp, ?vpt)) { + tup(sp, "taking the value of " + ast::path_name(vpt)) + } + }; + cx.tcx.sess.span_err + (msg._0, msg._1 + " will invalidate alias " + + ast::path_name(p) + ", which is still used"); + } +} + +fn deps(&scope sc, vec[def_num] roots) -> vec[uint] { + auto i = 0u; + auto result = []; + for (restrict r in sc) { + for (def_num dn in roots) { + if (vec::member(dn, r.bindings)) { + vec::push(result, i); + } + } + i += 1u; + } + ret result; +} + fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> rec(@ast::expr ex, option::t[ty::t] inner_mut, bool mut_in_box) { let option::t[ty::t] mut = none; diff --git a/src/lib/map.rs b/src/lib/map.rs index 396835bc1d69..854ab74df9a8 100644 --- a/src/lib/map.rs +++ b/src/lib/map.rs @@ -131,7 +131,8 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { { for (bucket[K, V] b in oldbkts) { alt (b) { - case (some(?k, ?v)) { + case (some(?k_, ?v_)) { + auto k = k_; auto v = v_; insert_common[K, V](hasher, eqer, newbkts, nnewbkts, k, v); }