Zero locals with initializers that may break or terminate. Closes #787
This commit is contained in:
parent
c011f13144
commit
c1f2394245
2 changed files with 92 additions and 1 deletions
|
@ -4758,6 +4758,11 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
|
||||||
let llptr = bcx.fcx.lllocals.get(local.node.id);
|
let llptr = bcx.fcx.lllocals.get(local.node.id);
|
||||||
// Make a note to drop this slot on the way out.
|
// Make a note to drop this slot on the way out.
|
||||||
add_clean(bcx, llptr, ty);
|
add_clean(bcx, llptr, ty);
|
||||||
|
|
||||||
|
if (must_zero(local)) {
|
||||||
|
bcx = zero_alloca(bcx, llptr, ty).bcx;
|
||||||
|
}
|
||||||
|
|
||||||
alt local.node.init {
|
alt local.node.init {
|
||||||
some(init) {
|
some(init) {
|
||||||
alt init.op {
|
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 =
|
bcx =
|
||||||
trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
|
trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
|
||||||
bcx.fcx.lllocals, false);
|
bcx.fcx.lllocals, false);
|
||||||
ret rslt(bcx, llptr);
|
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 {
|
fn zero_alloca(cx: &@block_ctxt, llptr: ValueRef, t: ty::t) -> result {
|
||||||
|
|
51
src/test/run-pass/terminate-in-initializer.rs
Normal file
51
src/test/run-pass/terminate-in-initializer.rs
Normal 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();
|
||||||
|
}
|
Loading…
Reference in a new issue