Skip to content

Commit cca6335

Browse files
committed
Implement the "attempted dynamic environment-capture" error in rustc.
1 parent 4bd8dcc commit cca6335

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed

src/comp/driver/rustc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import front.token;
66
import front.eval;
77
import middle.trans;
88
import middle.resolve;
9+
import middle.capture;
910
import middle.ty;
1011
import middle.typeck;
1112
import middle.typestate_check;
@@ -67,6 +68,7 @@ impure fn compile_input(session.session sess,
6768
if (parse_only) {ret;}
6869
crate = creader.read_crates(sess, crate, library_search_paths);
6970
crate = resolve.resolve_crate(sess, crate);
71+
capture.check_for_captures(sess, crate);
7072
auto typeck_result = typeck.check_crate(sess, crate);
7173
crate = typeck_result._0;
7274
auto type_cache = typeck_result._1;

src/comp/middle/capture.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import driver.session;
2+
import front.ast;
3+
import std.map.hashmap;
4+
import std.option;
5+
import std.option.some;
6+
import std.option.none;
7+
import std._int;
8+
import util.common;
9+
10+
type fn_id_of_local = std.map.hashmap[ast.def_id, ast.def_id];
11+
type env = rec(option.t[ast.def_id] current_context, // fn or obj
12+
fn_id_of_local idmap,
13+
session.session sess);
14+
15+
fn update_env_for_item(&env e, @ast.item i) -> env {
16+
alt (i.node) {
17+
case (ast.item_fn(?name, _, _, ?id, _)) {
18+
ret rec(current_context = some(id) with e);
19+
}
20+
case (ast.item_obj(_, _, _, ?ids, _)) {
21+
ret rec(current_context = some(ids.ty) with e);
22+
}
23+
case (_) {
24+
ret e;
25+
}
26+
}
27+
}
28+
29+
fn update_env_for_expr(&env e, @ast.expr x) -> env {
30+
alt (x.node) {
31+
case (ast.expr_for(?d, _, _, _)) {
32+
alt (d.node) {
33+
case (ast.decl_local(?local)) {
34+
auto curr_context =
35+
option.get[ast.def_id](e.current_context);
36+
e.idmap.insert(local.id, curr_context);
37+
}
38+
case (_) {
39+
}
40+
}
41+
}
42+
case (ast.expr_for_each(?d, _, _, _)) {
43+
alt (d.node) {
44+
case (ast.decl_local(?local)) {
45+
auto curr_context =
46+
option.get[ast.def_id](e.current_context);
47+
e.idmap.insert(local.id, curr_context);
48+
}
49+
case (_) {
50+
}
51+
}
52+
}
53+
case (_) { }
54+
}
55+
ret e;
56+
}
57+
58+
fn update_env_for_block(&env e, &ast.block b) -> env {
59+
auto curr_context = option.get[ast.def_id](e.current_context);
60+
61+
for each (@tup(ast.ident, ast.block_index_entry) it in
62+
b.node.index.items()) {
63+
alt (it._1) {
64+
case (ast.bie_local(?local)) {
65+
e.idmap.insert(local.id, curr_context);
66+
}
67+
case (_) {
68+
}
69+
}
70+
}
71+
72+
ret e;
73+
}
74+
75+
fn fold_expr_path(&env e, &ast.span sp, &ast.path p, &option.t[ast.def] d,
76+
ast.ann a) -> @ast.expr {
77+
auto local_id;
78+
alt (option.get[ast.def](d)) {
79+
case (ast.def_local(?id)) {
80+
local_id = id;
81+
}
82+
case (_) {
83+
ret @fold.respan[ast.expr_](sp, ast.expr_path(p, d, a));
84+
}
85+
}
86+
87+
auto curr_context = option.get[ast.def_id](e.current_context);
88+
auto x = ast.def_id_of_def(option.get[ast.def](d));
89+
auto def_context = option.get[ast.def_id](e.idmap.find(x));
90+
91+
if (curr_context != def_context) {
92+
e.sess.span_err(sp, "attempted dynamic environment-capture");
93+
}
94+
95+
ret @fold.respan[ast.expr_](sp, ast.expr_path(p, d, a));
96+
}
97+
98+
fn check_for_captures(session.session sess, @ast.crate crate) {
99+
let fold.ast_fold[env] fld = fold.new_identity_fold[env]();
100+
fld = @rec( update_env_for_item = bind update_env_for_item(_,_),
101+
update_env_for_block = bind update_env_for_block(_,_),
102+
update_env_for_expr = bind update_env_for_expr(_,_),
103+
fold_expr_path = bind fold_expr_path(_,_,_,_,_)
104+
with *fld);
105+
auto idmap = common.new_def_hash[ast.def_id]();
106+
auto e = rec(current_context = none[ast.def_id], idmap = idmap,
107+
sess = sess);
108+
fold.fold_crate[env](e, fld, crate);
109+
}
110+
111+
// Local Variables:
112+
// mode: rust
113+
// fill-column: 78;
114+
// indent-tabs-mode: nil
115+
// c-basic-offset: 4
116+
// buffer-file-coding-system: utf-8-unix
117+
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
118+
// End:

src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod middle {
1818
mod fold;
1919
mod metadata;
2020
mod resolve;
21+
mod capture;
2122
mod trans;
2223
mod ty;
2324
mod typeck;

src/test/compile-fail/capture1.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// -*- rust -*-
2+
3+
// error-pattern: attempted dynamic environment-capture
4+
5+
fn main() {
6+
7+
fn foo() -> int {
8+
ret bar;
9+
}
10+
11+
let int bar = 5;
12+
}

src/test/compile-fail/capture2.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// -*- rust -*-
2+
3+
// error-pattern: attempted dynamic environment-capture
4+
5+
fn f(bool x) {
6+
}
7+
8+
state obj foobar(bool x) {
9+
drop {
10+
auto y = x;
11+
fn test() {
12+
f(y);
13+
}
14+
}
15+
}
16+
17+
fn main() {
18+
}

0 commit comments

Comments
 (0)