mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-14 16:03:17 +00:00
Zero locals with initializers that may break or terminate. Closes #787
This commit is contained in:
parent
c011f13144
commit
c1f2394245
@ -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 {
|
||||
|
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 New Issue
Block a user