Skip to content

Commit b4217b3

Browse files
committed
Add a pass that checks that blocks are only used in safe ways
Closes #1188
1 parent 86c1f16 commit b4217b3

File tree

5 files changed

+47
-6
lines changed

5 files changed

+47
-6
lines changed

src/comp/driver/rustc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
139139
bind freevars::annotate_freevars(def_map, crate));
140140
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
141141
time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate));
142+
time(time_passes, "block-use checking",
143+
bind middle::block_use::check_crate(ty_cx, crate));
142144
time(time_passes, "function usage",
143145
bind fn_usage::check_crate_fn_usage(ty_cx, crate));
144146
time(time_passes, "alt checking",

src/comp/middle/block_use.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import syntax::visit;
2+
import syntax::ast::*;
3+
4+
type ctx = {tcx: ty::ctxt, mutable allow_block: bool};
5+
6+
fn check_crate(tcx: ty::ctxt, crate: @crate) {
7+
let cx = {tcx: tcx, mutable allow_block: false};
8+
let v = visit::mk_vt(@{visit_expr: visit_expr
9+
with *visit::default_visitor()});
10+
visit::visit_crate(*crate, cx, v);
11+
}
12+
13+
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
14+
if !cx.allow_block {
15+
alt ty::struct(cx.tcx, ty::expr_ty(cx.tcx, ex)) {
16+
ty::ty_fn(proto_block., _, _, _, _) {
17+
cx.tcx.sess.span_err(ex.span, "expressions with block type \
18+
can only appear in callee or (by-ref) argument position");
19+
}
20+
_ {}
21+
}
22+
}
23+
let outer = cx.allow_block;
24+
alt ex.node {
25+
expr_call(f, args, _) {
26+
cx.allow_block = true;
27+
v.visit_expr(f, cx, v);
28+
let i = 0u;
29+
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
30+
cx.allow_block = arg_t.mode == by_ref;
31+
v.visit_expr(args[i], cx, v);
32+
i += 1u;
33+
}
34+
}
35+
_ {
36+
cx.allow_block = false;
37+
visit::visit_expr(ex, cx, v);
38+
}
39+
}
40+
cx.allow_block = outer;
41+
}

src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod middle {
3131
mod mut;
3232
mod alias;
3333
mod last_use;
34+
mod block_use;
3435
mod kind;
3536
mod freevars;
3637
mod shape;

src/test/compile-fail/block-copy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern: copying a noncopyable value
1+
// error-pattern: block type can only appear
22

33
fn lol(f: block()) -> block() { ret f; }
44
fn main() { let i = 8; let f = lol(block () { log_err i; }); f(); }
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// error-pattern:Tried to deinitialize a variable declared in a different
2-
fn force(f: block() -> int) -> int { ret f(); }
2+
fn force(f: block()) { f(); }
33
fn main() {
44
let x = @{x: 17, y: 2};
55
let y = @{x: 5, y: 5};
66

7-
let f = {|i| log_err i; x <- y; ret 7; };
8-
assert (f(5) == 7);
9-
log_err x;
10-
log_err y;
7+
force({|| x <- y;});
118
}

0 commit comments

Comments
 (0)