Zero locals with initializers that may break or terminate. Closes #787

This commit is contained in:
Brian Anderson 2011-08-23 15:45:24 -07:00
parent c011f13144
commit c1f2394245
2 changed files with 92 additions and 1 deletions

View file

@ -4758,6 +4758,11 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
let llptr = bcx.fcx.lllocals.get(local.node.id);
// Make a note to drop this slot on the way out.
add_clean(bcx, llptr, ty);
if (must_zero(local)) {
bcx = zero_alloca(bcx, llptr, ty).bcx;
}
alt local.node.init {
some(init) {
alt init.op {
@ -4775,12 +4780,47 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
}
}
}
_ { bcx = zero_alloca(bcx, llptr, ty).bcx; }
_ { }
}
bcx =
trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
bcx.fcx.lllocals, false);
ret rslt(bcx, llptr);
fn must_zero(local: &@ast::local) -> bool {
alt local.node.init {
some(init) {
might_not_init(init.expr)
}
none. { true }
}
}
fn might_not_init(expr: &@ast::expr) -> bool {
type env = @mutable bool;
let e = @mutable false;
let visitor = visit::mk_vt(@{
visit_expr: fn(ex: &@ast::expr, e: &env, v: &vt<env>) {
// FIXME: Probably also need to account for expressions that
// fail but since we don't unwind yet, it doesn't seem to be a
// problem
let might_not_init = alt ex.node {
ast::expr_ret(_) { true }
ast::expr_break. { true }
ast::expr_cont. { true }
_ { false }
};
if might_not_init {
*e = true;
} else {
visit::visit_expr(ex, e, v);
}
}
with *visit::default_visitor()
});
visitor.visit_expr(expr, e, visitor);
ret *e;
}
}
fn zero_alloca(cx: &@block_ctxt, llptr: ValueRef, t: ty::t) -> result {

View file

@ -0,0 +1,51 @@
// Issue #787
// Don't try to clean up uninitizaed locals
use std;
fn test_break() {
while true {
let x: @int = break;
}
}
fn test_cont() {
let i = 0;
while i < 1 {
i += 1;
let x: @int = cont;
}
}
fn test_ret() {
let x: @int = ret;
}
fn test_fail() {
fn f() {
std::task::unsupervise();
let x: @int = fail;
}
let g = f;
std::task::spawn(g);
}
fn test_fail_indirect() {
fn f() -> ! {
fail;
}
fn g() {
std::task::unsupervise();
let x: @int = f();
}
let h = g;
std::task::spawn(h);
}
fn main() {
test_break();
test_cont();
test_ret();
test_fail();
test_fail_indirect();
}