Add support for break and cont to rustc
Testing proper cleanup is hampered by https://github.com/graydon/rust/issues/293
This commit is contained in:
parent
9c5affda1a
commit
6ecdc04788
@ -246,6 +246,8 @@ tag expr_ {
|
||||
expr_path(path, option.t[def], ann);
|
||||
expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
|
||||
expr_fail;
|
||||
expr_break;
|
||||
expr_cont;
|
||||
expr_ret(option.t[@expr]);
|
||||
expr_put(option.t[@expr]);
|
||||
expr_be(@expr);
|
||||
|
@ -111,6 +111,8 @@ impure fn new_reader(io.reader rdr, str filename) -> reader
|
||||
|
||||
keywords.insert("for", token.FOR);
|
||||
keywords.insert("each", token.EACH);
|
||||
keywords.insert("break", token.BREAK);
|
||||
keywords.insert("cont", token.CONT);
|
||||
keywords.insert("put", token.PUT);
|
||||
keywords.insert("ret", token.RET);
|
||||
keywords.insert("be", token.BE);
|
||||
|
@ -829,6 +829,16 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
|
||||
}
|
||||
}
|
||||
|
||||
case (token.BREAK) {
|
||||
p.bump();
|
||||
ex = ast.expr_break;
|
||||
}
|
||||
|
||||
case (token.CONT) {
|
||||
p.bump();
|
||||
ex = ast.expr_cont;
|
||||
}
|
||||
|
||||
case (token.PUT) {
|
||||
p.bump();
|
||||
alt (p.peek()) {
|
||||
|
@ -74,6 +74,9 @@ tag token {
|
||||
ALT;
|
||||
CASE;
|
||||
|
||||
BREAK;
|
||||
CONT;
|
||||
|
||||
FAIL;
|
||||
DROP;
|
||||
|
||||
@ -242,6 +245,9 @@ fn to_str(token t) -> str {
|
||||
case (ALT) { ret "alt"; }
|
||||
case (CASE) { ret "case"; }
|
||||
|
||||
case (BREAK) { ret "break"; }
|
||||
case (CONT) { ret "cont"; }
|
||||
|
||||
case (FAIL) { ret "fail"; }
|
||||
case (DROP) { ret "drop"; }
|
||||
|
||||
|
@ -170,6 +170,10 @@ type ast_fold[ENV] =
|
||||
|
||||
(fn(&ENV e, &span sp) -> @expr) fold_expr_fail,
|
||||
|
||||
(fn(&ENV e, &span sp) -> @expr) fold_expr_break,
|
||||
|
||||
(fn(&ENV e, &span sp) -> @expr) fold_expr_cont,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&option.t[@expr] rv) -> @expr) fold_expr_ret,
|
||||
|
||||
@ -695,6 +699,14 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
|
||||
ret fld.fold_expr_fail(env_, e.span);
|
||||
}
|
||||
|
||||
case (ast.expr_break) {
|
||||
ret fld.fold_expr_break(env_, e.span);
|
||||
}
|
||||
|
||||
case (ast.expr_cont) {
|
||||
ret fld.fold_expr_cont(env_, e.span);
|
||||
}
|
||||
|
||||
case (ast.expr_ret(?oe)) {
|
||||
auto oee = none[@expr];
|
||||
alt (oe) {
|
||||
@ -1266,6 +1278,14 @@ fn identity_fold_expr_fail[ENV](&ENV env, &span sp) -> @expr {
|
||||
ret @respan(sp, ast.expr_fail);
|
||||
}
|
||||
|
||||
fn identity_fold_expr_break[ENV](&ENV env, &span sp) -> @expr {
|
||||
ret @respan(sp, ast.expr_break);
|
||||
}
|
||||
|
||||
fn identity_fold_expr_cont[ENV](&ENV env, &span sp) -> @expr {
|
||||
ret @respan(sp, ast.expr_cont);
|
||||
}
|
||||
|
||||
fn identity_fold_expr_ret[ENV](&ENV env, &span sp,
|
||||
&option.t[@expr] rv) -> @expr {
|
||||
ret @respan(sp, ast.expr_ret(rv));
|
||||
@ -1565,6 +1585,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
|
||||
fold_expr_path = bind identity_fold_expr_path[ENV](_,_,_,_,_),
|
||||
fold_expr_ext = bind identity_fold_expr_ext[ENV](_,_,_,_,_,_,_),
|
||||
fold_expr_fail = bind identity_fold_expr_fail[ENV](_,_),
|
||||
fold_expr_break = bind identity_fold_expr_break[ENV](_,_),
|
||||
fold_expr_cont = bind identity_fold_expr_cont[ENV](_,_),
|
||||
fold_expr_ret = bind identity_fold_expr_ret[ENV](_,_,_),
|
||||
fold_expr_put = bind identity_fold_expr_put[ENV](_,_,_),
|
||||
fold_expr_be = bind identity_fold_expr_be[ENV](_,_,_),
|
||||
|
@ -130,6 +130,7 @@ tag cleanup {
|
||||
|
||||
tag block_kind {
|
||||
SCOPE_BLOCK;
|
||||
LOOP_SCOPE_BLOCK(option.t[@block_ctxt], @block_ctxt);
|
||||
NON_SCOPE_BLOCK;
|
||||
}
|
||||
|
||||
@ -990,7 +991,7 @@ fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
|
||||
}
|
||||
|
||||
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
|
||||
if (cx.kind == SCOPE_BLOCK) {
|
||||
if (cx.kind != NON_SCOPE_BLOCK) {
|
||||
ret cx;
|
||||
}
|
||||
alt (cx.parent) {
|
||||
@ -3043,13 +3044,15 @@ fn trans_for(@block_ctxt cx,
|
||||
@ast.decl decl,
|
||||
@ast.expr seq,
|
||||
&ast.block body) -> result {
|
||||
|
||||
fn inner(@block_ctxt cx,
|
||||
@ast.local local, ValueRef curr,
|
||||
@ty.t t, ast.block body) -> result {
|
||||
@ty.t t, ast.block body,
|
||||
@block_ctxt outer_next_cx) -> result {
|
||||
|
||||
auto scope_cx = new_scope_block_ctxt(cx, "for loop scope");
|
||||
auto next_cx = new_sub_block_ctxt(cx, "next");
|
||||
auto scope_cx =
|
||||
new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
|
||||
outer_next_cx, "for loop scope");
|
||||
|
||||
cx.build.Br(scope_cx.llbb);
|
||||
auto local_res = alloc_local(scope_cx, local);
|
||||
@ -3069,10 +3072,13 @@ fn trans_for(@block_ctxt cx,
|
||||
}
|
||||
}
|
||||
|
||||
auto next_cx = new_sub_block_ctxt(cx, "next");
|
||||
auto seq_ty = ty.expr_ty(seq);
|
||||
auto seq_res = trans_expr(cx, seq);
|
||||
ret iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
|
||||
bind inner(_, local, _, _, body));
|
||||
auto it = iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
|
||||
bind inner(_, local, _, _, body, next_cx));
|
||||
it.bcx.build.Br(next_cx.llbb);
|
||||
ret res(next_cx, it.val);
|
||||
}
|
||||
|
||||
|
||||
@ -3308,8 +3314,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
|
||||
&ast.block body) -> result {
|
||||
|
||||
auto cond_cx = new_scope_block_ctxt(cx, "while cond");
|
||||
auto body_cx = new_scope_block_ctxt(cx, "while loop body");
|
||||
auto next_cx = new_sub_block_ctxt(cx, "next");
|
||||
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
|
||||
next_cx, "while loop body");
|
||||
|
||||
auto body_res = trans_block(body_cx, body);
|
||||
auto cond_res = trans_expr(cond_cx, cond);
|
||||
@ -3326,8 +3333,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
|
||||
fn trans_do_while(@block_ctxt cx, &ast.block body,
|
||||
@ast.expr cond) -> result {
|
||||
|
||||
auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
|
||||
auto next_cx = new_sub_block_ctxt(cx, "next");
|
||||
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
|
||||
next_cx, "do-while loop body");
|
||||
|
||||
auto body_res = trans_block(body_cx, body);
|
||||
auto cond_res = trans_expr(body_res.bcx, cond);
|
||||
@ -4599,6 +4607,14 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
|
||||
ret trans_check_expr(cx, a);
|
||||
}
|
||||
|
||||
case (ast.expr_break) {
|
||||
ret trans_break(cx);
|
||||
}
|
||||
|
||||
case (ast.expr_cont) {
|
||||
ret trans_cont(cx);
|
||||
}
|
||||
|
||||
case (ast.expr_ret(?e)) {
|
||||
ret trans_ret(cx, e);
|
||||
}
|
||||
@ -4770,6 +4786,47 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
|
||||
ret res(bcx, bcx.build.FastCall(llcallee, llargs));
|
||||
}
|
||||
|
||||
fn trans_break_cont(@block_ctxt cx, bool to_end) -> result {
|
||||
auto bcx = cx;
|
||||
// Locate closest loop block, outputting cleanup as we go.
|
||||
auto cleanup_cx = cx;
|
||||
while (true) {
|
||||
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
||||
alt (cleanup_cx.kind) {
|
||||
case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
|
||||
if (to_end) {
|
||||
bcx.build.Br(_break.llbb);
|
||||
} else {
|
||||
alt (_cont) {
|
||||
case (option.some[@block_ctxt](?_cont)) {
|
||||
bcx.build.Br(_cont.llbb);
|
||||
}
|
||||
case (_) {
|
||||
bcx.build.Br(cleanup_cx.llbb);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret res(new_sub_block_ctxt(cx, "unreachable"), C_nil());
|
||||
}
|
||||
case (_) {
|
||||
alt (cleanup_cx.parent) {
|
||||
case (parent_some(?cx)) { cleanup_cx = cx; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret res(cx, C_nil()); // Never reached. Won't compile otherwise.
|
||||
}
|
||||
|
||||
fn trans_break(@block_ctxt cx) -> result {
|
||||
ret trans_break_cont(cx, true);
|
||||
}
|
||||
|
||||
fn trans_cont(@block_ctxt cx) -> result {
|
||||
ret trans_break_cont(cx, false);
|
||||
}
|
||||
|
||||
|
||||
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
|
||||
auto bcx = cx;
|
||||
auto val = C_nil();
|
||||
@ -5033,6 +5090,12 @@ fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
|
||||
ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
|
||||
}
|
||||
|
||||
fn new_loop_scope_block_ctxt(@block_ctxt bcx, option.t[@block_ctxt] _cont,
|
||||
@block_ctxt _break, str n) -> @block_ctxt {
|
||||
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
|
||||
LOOP_SCOPE_BLOCK(_cont, _break), n);
|
||||
}
|
||||
|
||||
// Use this when you're making a general CFG BB within a scope.
|
||||
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
|
||||
ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
|
||||
@ -5043,7 +5106,7 @@ fn trans_block_cleanups(@block_ctxt cx,
|
||||
@block_ctxt cleanup_cx) -> @block_ctxt {
|
||||
auto bcx = cx;
|
||||
|
||||
if (cleanup_cx.kind != SCOPE_BLOCK) {
|
||||
if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
|
||||
check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
|
||||
}
|
||||
|
||||
|
@ -1413,6 +1413,8 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
|
||||
}
|
||||
case (ast.expr_fail) { e_1 = e.node; }
|
||||
case (ast.expr_log(_)) { e_1 = e.node; }
|
||||
case (ast.expr_break) { e_1 = e.node; }
|
||||
case (ast.expr_cont) { e_1 = e.node; }
|
||||
case (ast.expr_ret(_)) { e_1 = e.node; }
|
||||
case (ast.expr_put(_)) { e_1 = e.node; }
|
||||
case (ast.expr_be(_)) { e_1 = e.node; }
|
||||
@ -1806,6 +1808,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
|
||||
ret expr;
|
||||
}
|
||||
|
||||
case (ast.expr_break) {
|
||||
ret expr;
|
||||
}
|
||||
|
||||
case (ast.expr_cont) {
|
||||
ret expr;
|
||||
}
|
||||
|
||||
case (ast.expr_ret(?expr_opt)) {
|
||||
alt (expr_opt) {
|
||||
case (none[@ast.expr]) {
|
||||
|
40
src/test/run-pass/break.rs
Normal file
40
src/test/run-pass/break.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// xfail-boot
|
||||
|
||||
fn main() {
|
||||
auto i = 0;
|
||||
while (i < 20) {
|
||||
i += 1;
|
||||
if (i == 10) { break; }
|
||||
}
|
||||
check(i == 10);
|
||||
|
||||
do {
|
||||
i += 1;
|
||||
if (i == 20) { break; }
|
||||
} while (i < 30);
|
||||
check(i == 20);
|
||||
|
||||
for (int x in vec(1, 2, 3, 4, 5, 6)) {
|
||||
if (x == 3) { break; }
|
||||
check(x <= 3);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < 10) {
|
||||
i += 1;
|
||||
if (i % 2 == 0) { cont; }
|
||||
check(i % 2 != 0);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
i += 1;
|
||||
if (i % 2 == 0) { cont; }
|
||||
check(i % 2 != 0);
|
||||
} while (i < 10);
|
||||
|
||||
for (int x in vec(1, 2, 3, 4, 5, 6)) {
|
||||
if (x % 2 == 0) { cont; }
|
||||
check(x % 2 != 0);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user