about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-06-09 14:19:13 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-06-09 14:19:13 +0200
commit537d879dc1437744e375d58bcce14bc427d904a2 (patch)
tree7f8187e252bb2c8597aeee2d4293367a989441f2 /src/comp
parentbeda82ddf1f482f286a8d9af3402626dc56d6fea (diff)
downloadrust-537d879dc1437744e375d58bcce14bc427d904a2.tar.gz
rust-537d879dc1437744e375d58bcce14bc427d904a2.zip
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.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/alias.rs59
1 files changed, 41 insertions, 18 deletions
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index fa978ef53c0..bad328e028c 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;