diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a945c88e2a68b..fca1c6c0bc23b 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1026,6 +1026,18 @@ fn find_scope_cx(@block_ctxt cx) -> @block_ctxt { } } +fn find_outer_scope_cx(@block_ctxt cx) -> @block_ctxt { + auto scope_cx = find_scope_cx(cx); + alt (cx.parent) { + case (parent_some(?b)) { + be find_scope_cx(b); + } + case (parent_none) { + fail; + } + } +} + fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef { auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b); ret cx.build.Select(cond, b, a); @@ -5368,8 +5380,49 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { case (some[@ast.expr](?e)) { r = trans_expr(bcx, e); bcx = r.bcx; + if (is_terminated(bcx)) { ret r; + } else { + auto r_ty = ty.expr_ty(e); + + if (ty.type_is_boxed(r_ty)) { + // The value resulting from the block gets copied into an + // alloca created in an outer scope and its refcount + // bumped so that it can escape this block. This means + // that it will definitely live until the end of the + // enclosing scope, even if nobody uses it, which may be + // something of a surprise. + + // It's possible we never hit this block, so the alloca + // must be initialized to null, then when the potential + // value finally goes out of scope the drop glue will see + // that it was never used and ignore it. + + // NB: Here we're building and initalizing the alloca in + // the alloca context, not this block's context. + auto res_alloca = alloc_ty(bcx, r_ty); + auto alloca_ty = type_of(bcx.fcx.ccx, r_ty); + auto builder = new_builder(bcx.fcx.llallocas); + builder.Store(C_null(alloca_ty), res_alloca.val); + + // Now we're working in our own block context again + auto res_copy = copy_ty(bcx, INIT, + res_alloca.val, r.val, r_ty); + bcx = res_copy.bcx; + + fn drop_hoisted_ty(@block_ctxt cx, + ValueRef alloca_val, + @ty.t t) -> result { + auto reg_val = load_scalar_or_boxed(cx, + alloca_val, t); + ret drop_ty(cx, reg_val, t); + } + + auto cleanup = bind drop_hoisted_ty(_, res_alloca.val, + r_ty); + find_outer_scope_cx(bcx).cleanups += vec(clean(cleanup)); + } } } case (none[@ast.expr]) { diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index d478227ce2278..f3b0f3fe97939 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -32,6 +32,24 @@ fn ty_to_str(&@ast.ty ty) -> str { ret writer.get_str(); } +fn block_to_str(&ast.block blk) -> str { + auto writer = io.string_writer(); + auto s = @rec(s=pp.mkstate(writer.get_writer(), 78u), + comments=option.none[vec[lexer.cmnt]], + mutable cur_cmnt=0u); + print_block(s, blk); + ret writer.get_str(); +} + +fn expr_to_str(&@ast.expr e) -> str { + auto writer = io.string_writer(); + auto s = @rec(s=pp.mkstate(writer.get_writer(), 78u), + comments=option.none[vec[lexer.cmnt]], + mutable cur_cmnt=0u); + print_expr(s, e); + ret writer.get_str(); +} + impure fn hbox(ps s) { pp.hbox(s.s, indent_unit); } diff --git a/src/test/run-pass/expr-alt.rs b/src/test/run-pass/expr-alt.rs new file mode 100644 index 0000000000000..22cdf32a67230 --- /dev/null +++ b/src/test/run-pass/expr-alt.rs @@ -0,0 +1,31 @@ +// xfail-boot +// xfail-stage0 +// -*- rust -*- + +// Tests for using alt as an expression + +fn test() { + let bool res = alt (true) { + case (true) { + true + } + case (false) { + false + } + }; + check (res); + + res = alt(false) { + case (true) { + false + } + case (false) { + true + } + }; + check (res); +} + +fn main() { + test(); +} diff --git a/src/test/run-pass/expr-block-box.rs b/src/test/run-pass/expr-block-box.rs new file mode 100644 index 0000000000000..e8ab62091a59d --- /dev/null +++ b/src/test/run-pass/expr-block-box.rs @@ -0,0 +1,10 @@ +// xfail-boot +// -*- rust -*- + +fn main() { + auto x = { + @100 + }; + + check (*x == 100); +} diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs new file mode 100644 index 0000000000000..fc34d112419d7 --- /dev/null +++ b/src/test/run-pass/expr-block-generic.rs @@ -0,0 +1,56 @@ +// xfail-boot +// xfail-stage0 +// -*- rust -*- + +// Tests for standalone blocks as expressions with dynamic type sizes + +type compare[T] = fn(&T t1, &T t2) -> bool; + +fn test_generic[T](&T expected, &compare[T] eq) { + let T actual = { expected }; + check (eq(expected, actual)); +} + +fn test_bool() { + fn compare_bool(&bool b1, &bool b2) -> bool { + ret b1 == b2; + } + auto eq = bind compare_bool(_, _); + test_generic[bool](true, eq); +} + + +fn test_tup() { + type t = tup(int, int); + fn compare_tup(&t t1, &t t2) -> bool { + ret t1 == t2; + } + auto eq = bind compare_tup(_, _); + test_generic[t](tup(1, 2), eq); +} + +fn test_vec() { + fn compare_vec(&vec[int] v1, &vec[int] v2) -> bool { + ret v1 == v2; + } + auto eq = bind compare_vec(_, _); + test_generic[vec[int]](vec(1, 2), eq); +} + +fn test_box() { + fn compare_box(&@bool b1, &@bool b2) -> bool { + ret *b1 == *b2; + } + auto eq = bind compare_box(_, _); + test_generic[@bool](@true, eq); +} + +fn main() { + test_bool(); + test_tup(); + // FIXME: These two don't pass yet + test_vec(); + test_box(); +} + + diff --git a/src/test/run-pass/expr-block.rs b/src/test/run-pass/expr-block.rs new file mode 100644 index 0000000000000..ecc6f04a34029 --- /dev/null +++ b/src/test/run-pass/expr-block.rs @@ -0,0 +1,31 @@ +// xfail-boot +// -*- rust -*- + +// Tests for standalone blocks as expressions + +fn test_basic() { + let bool res = { true }; + check (res); +} + +fn test_rec() { + auto res = { rec(v1 = 10, v2 = 20) }; + check (res.v2 == 20); +} + +fn test_filled_with_stuff() { + auto res = { + auto a = 0; + while (a < 10) { + a += 1; + } + a + }; + check (res == 10); +} + +fn main() { + test_basic(); + test_rec(); + test_filled_with_stuff(); +} diff --git a/src/test/run-pass/expr-if-box.rs b/src/test/run-pass/expr-if-box.rs index 98503211fc2c3..a629c9c9bc464 100644 --- a/src/test/run-pass/expr-if-box.rs +++ b/src/test/run-pass/expr-if-box.rs @@ -1,5 +1,4 @@ // xfail-boot -// xfail-stage0 // -*- rust -*- // Tests for if as expressions returning boxed types @@ -9,6 +8,12 @@ fn test_box() { check (*res == 100); } +fn test_str() { + auto res = if (true) { "happy" } else { "sad" }; + check (res == "happy"); +} + fn main() { test_box(); -} \ No newline at end of file + test_str(); +} diff --git a/src/test/run-pass/expr-if.rs b/src/test/run-pass/expr-if.rs index e69a629f9d055..7c99f2ea82e1c 100644 --- a/src/test/run-pass/expr-if.rs +++ b/src/test/run-pass/expr-if.rs @@ -80,11 +80,6 @@ fn test_if_as_block_result() { check (res); } -fn test_str() { - auto res = if (true) { "happy" } else { "sad" }; - check (res == "happy"); -} - fn main() { test_if(); test_else(); @@ -94,5 +89,4 @@ fn main() { test_inferrence(); test_if_as_if_condition(); test_if_as_block_result(); - test_str(); }