Skip to content

Commit a6f3906

Browse files
committed
---
yaml --- r: 6850 b: refs/heads/master c: 55a2fd1 h: refs/heads/master v: v3
1 parent ffb609b commit a6f3906

15 files changed

+306
-54
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 41ae146057431d99d5ab5c87d385dbf787a10ea2
2+
refs/heads/master: 55a2fd18ec8f2e9aeee699296b7a500b49ff0c5e

trunk/src/comp/middle/capture.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import syntax::{ast, ast_util};
2+
import std::map;
3+
4+
export capture_mode;
5+
export capture_var;
6+
export capture_map;
7+
export check_capture_clause;
8+
export compute_capture_vars;
9+
export cap_copy;
10+
export cap_move;
11+
export cap_drop;
12+
export cap_ref;
13+
14+
tag capture_mode {
15+
cap_copy; //< Copy the value into the closure.
16+
cap_move; //< Move the value into the closure.
17+
cap_drop; //< Drop value after creating closure.
18+
cap_ref; //< Reference directly from parent stack frame (block fn).
19+
}
20+
21+
type capture_var = {
22+
def: ast::def, //< The variable being accessed free.
23+
mode: capture_mode //< How is the variable being accessed.
24+
};
25+
26+
type capture_map = map::hashmap<ast::def_id, capture_var>;
27+
28+
// checks the capture clause for a fn_expr() and issues warnings or
29+
// errors for any irregularities which we identify.
30+
fn check_capture_clause(tcx: ty::ctxt,
31+
fn_expr_id: ast::node_id,
32+
fn_proto: ast::proto,
33+
cap_clause: ast::capture_clause) {
34+
let freevars = freevars::get_freevars(tcx, fn_expr_id);
35+
let seen_defs = map::new_int_hash();
36+
37+
let check_capture_item = lambda(&&cap_item: @ast::capture_item) {
38+
let cap_def = tcx.def_map.get(cap_item.id);
39+
if !vec::any(*freevars, {|fv| fv.def == cap_def}) {
40+
tcx.sess.span_warn(
41+
cap_item.span,
42+
#fmt("Captured variable '%s' not used in closure",
43+
cap_item.name));
44+
}
45+
46+
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
47+
if !seen_defs.insert(cap_def_id, ()) {
48+
tcx.sess.span_err(
49+
cap_item.span,
50+
#fmt("Variable '%s' captured more than once",
51+
cap_item.name));
52+
}
53+
};
54+
55+
let check_not_upvar = lambda(&&cap_item: @ast::capture_item) {
56+
alt tcx.def_map.get(cap_item.id) {
57+
ast::def_upvar(_, _, _) {
58+
tcx.sess.span_err(
59+
cap_item.span,
60+
#fmt("Upvars (like '%s') cannot be moved into a closure",
61+
cap_item.name));
62+
}
63+
_ {}
64+
}
65+
};
66+
67+
let check_block_captures = lambda(v: [@ast::capture_item]) {
68+
if check vec::is_not_empty(v) {
69+
let cap_item0 = vec::head(v);
70+
tcx.sess.span_err(
71+
cap_item0.span,
72+
"Cannot capture values explicitly with a block closure");
73+
}
74+
};
75+
76+
alt fn_proto {
77+
ast::proto_block. {
78+
check_block_captures(cap_clause.copies);
79+
check_block_captures(cap_clause.moves);
80+
}
81+
ast::proto_bare. | ast::proto_shared(_) | ast::proto_send. {
82+
vec::iter(cap_clause.copies, check_capture_item);
83+
vec::iter(cap_clause.moves, check_capture_item);
84+
vec::iter(cap_clause.moves, check_not_upvar);
85+
}
86+
}
87+
}
88+
89+
fn compute_capture_vars(tcx: ty::ctxt,
90+
fn_expr_id: ast::node_id,
91+
fn_proto: ast::proto,
92+
cap_clause: ast::capture_clause) -> [capture_var] {
93+
let freevars = freevars::get_freevars(tcx, fn_expr_id);
94+
let cap_map = map::new_int_hash();
95+
96+
vec::iter(cap_clause.copies) { |cap_item|
97+
let cap_def = tcx.def_map.get(cap_item.id);
98+
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
99+
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
100+
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
101+
}
102+
}
103+
104+
vec::iter(cap_clause.moves) { |cap_item|
105+
let cap_def = tcx.def_map.get(cap_item.id);
106+
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
107+
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
108+
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
109+
} else {
110+
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
111+
}
112+
}
113+
114+
let implicit_mode = alt fn_proto {
115+
ast::proto_block. { cap_ref }
116+
ast::proto_bare. | ast::proto_shared(_) | ast::proto_send. { cap_copy }
117+
};
118+
119+
vec::iter(*freevars) { |fvar|
120+
let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;
121+
alt cap_map.find(fvar_def_id) {
122+
option::some(_) { /* was explicitly named, do nothing */ }
123+
option::none. {
124+
cap_map.insert(fvar_def_id, {def:fvar.def, mode:implicit_mode});
125+
}
126+
}
127+
}
128+
129+
let result = [];
130+
cap_map.values { |cap_var| result += [cap_var]; }
131+
ret result;
132+
}

trunk/src/comp/middle/trans.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,7 +2566,11 @@ type generic_info =
25662566
static_tis: [option::t<@tydesc_info>],
25672567
tydescs: [ValueRef]};
25682568

2569-
tag lval_kind { temporary; owned; owned_imm; }
2569+
tag lval_kind {
2570+
temporary; //< Temporary value passed by value if of immediate type
2571+
owned; //< Non-temporary value passed by pointer
2572+
owned_imm; //< Non-temporary value passed by value
2573+
}
25702574
type local_var_result = {val: ValueRef, kind: lval_kind};
25712575
type lval_result = {bcx: @block_ctxt, val: ValueRef, kind: lval_kind};
25722576
tag callee_env { obj_env(ValueRef); null_env; is_closure; }
@@ -3550,12 +3554,13 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
35503554
assert op != ast::deref; // lvals are handled above
35513555
ret trans_unary(bcx, op, x, e.id, dest);
35523556
}
3553-
// NDM captures
35543557
ast::expr_fn(f, cap_clause) {
3555-
ret trans_closure::trans_expr_fn(bcx, f, e.span, e.id, dest);
3558+
ret trans_closure::trans_expr_fn(
3559+
bcx, f, e.span, e.id, *cap_clause, dest);
35563560
}
35573561
ast::expr_bind(f, args) {
3558-
ret trans_closure::trans_bind(bcx, f, args, e.id, dest);
3562+
ret trans_closure::trans_bind(
3563+
bcx, f, args, e.id, dest);
35593564
}
35603565
ast::expr_copy(a) {
35613566
if !expr_is_lval(bcx, a) {

trunk/src/comp/middle/trans_closure.rs

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ import trans::{
4343
// };
4444
// };
4545
//
46-
// NB: this is defined in the code in T_closure_ptr and
47-
// closure_ty_to_tuple_ty (below).
46+
// NB: this struct is defined in the code in trans_common::T_closure()
47+
// and mk_closure_ty() below. The former defines the LLVM version and
48+
// the latter the Rust equivalent. It occurs to me that these could
49+
// perhaps be unified, but currently they are not.
4850
//
4951
// Note that the closure carries a type descriptor that describes
5052
// itself. Trippy. This is needed because the precise types of the
@@ -64,8 +66,17 @@ import trans::{
6466
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6567

6668
tag environment_value {
69+
// Evaluate expr and store result in env (used for bind).
6770
env_expr(@ast::expr);
68-
env_direct(ValueRef, ty::t, bool);
71+
72+
// Copy the value from this llvm ValueRef into the environment.
73+
env_copy(ValueRef, ty::t, lval_kind);
74+
75+
// Move the value from this llvm ValueRef into the environment.
76+
env_move(ValueRef, ty::t, lval_kind);
77+
78+
// Access by reference (used for blocks).
79+
env_ref(ValueRef, ty::t, lval_kind);
6980
}
7081

7182
// Given a closure ty, emits a corresponding tuple ty
@@ -143,8 +154,10 @@ fn store_environment(
143154
let bound_tys = [];
144155
for bv in bound_values {
145156
bound_tys += [alt bv {
146-
env_direct(_, t, _) { t }
147-
env_expr(e) { ty::expr_ty(tcx, e) }
157+
env_copy(_, t, _) { t }
158+
env_move(_, t, _) { t }
159+
env_ref(_, t, _) { t }
160+
env_expr(e) { ty::expr_ty(tcx, e) }
148161
}];
149162
}
150163
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
@@ -239,17 +252,29 @@ fn store_environment(
239252
add_clean_temp_mem(bcx, bound.val, bound_tys[i]);
240253
temp_cleanups += [bound.val];
241254
}
242-
env_direct(val, ty, is_mem) {
243-
alt ck {
244-
ty::closure_shared. | ty::closure_send. {
245-
let val1 = is_mem ? load_if_immediate(bcx, val, ty) : val;
246-
bcx = trans::copy_val(bcx, INIT, bound.val, val1, ty);
247-
}
248-
ty::closure_block. {
249-
let addr = is_mem ? val : do_spill_noroot(bcx, val);
250-
Store(bcx, addr, bound.val);
251-
}
252-
}
255+
env_copy(val, ty, owned.) {
256+
let val1 = load_if_immediate(bcx, val, ty);
257+
bcx = trans::copy_val(bcx, INIT, bound.val, val1, ty);
258+
}
259+
env_copy(val, ty, owned_imm.) {
260+
bcx = trans::copy_val(bcx, INIT, bound.val, val, ty);
261+
}
262+
env_copy(_, _, temporary.) {
263+
fail "Cannot capture temporary upvar";
264+
}
265+
env_move(val, ty, kind) {
266+
let src = {bcx:bcx, val:val, kind:kind};
267+
bcx = move_val(bcx, INIT, bound.val, src, ty);
268+
}
269+
env_ref(val, ty, owned.) {
270+
Store(bcx, val, bound.val);
271+
}
272+
env_ref(val, ty, owned_imm.) {
273+
let addr = do_spill_noroot(bcx, val);
274+
Store(bcx, addr, bound.val);
275+
}
276+
env_ref(_, _, temporary.) {
277+
fail "Cannot capture temporary upvar";
253278
}
254279
}
255280
}
@@ -260,25 +285,38 @@ fn store_environment(
260285

261286
// Given a context and a list of upvars, build a closure. This just
262287
// collects the upvars and packages them up for store_environment.
263-
fn build_closure(cx: @block_ctxt,
264-
upvars: freevar_info,
288+
fn build_closure(bcx0: @block_ctxt,
289+
cap_vars: [capture::capture_var],
265290
ck: ty::closure_kind)
266291
-> closure_result {
267292
// If we need to, package up the iterator body to call
268293
let env_vals = [];
269-
let tcx = bcx_tcx(cx);
270-
// Package up the upvars
271-
vec::iter(*upvars) { |upvar|
272-
let lv = trans_local_var(cx, upvar.def);
273-
let nid = ast_util::def_id_of_def(upvar.def).node;
294+
let bcx = bcx0;
295+
let tcx = bcx_tcx(bcx);
296+
297+
// Package up the captured upvars
298+
vec::iter(cap_vars) { |cap_var|
299+
let lv = trans_local_var(bcx, cap_var.def);
300+
let nid = ast_util::def_id_of_def(cap_var.def).node;
274301
let ty = ty::node_id_to_monotype(tcx, nid);
275-
alt ck {
276-
ty::closure_block. { ty = ty::mk_mut_ptr(tcx, ty); }
277-
ty::closure_send. | ty::closure_shared. {}
302+
alt cap_var.mode {
303+
capture::cap_ref. {
304+
assert ck == ty::closure_block;
305+
ty = ty::mk_mut_ptr(tcx, ty);
306+
env_vals += [env_ref(lv.val, ty, lv.kind)];
307+
}
308+
capture::cap_copy. {
309+
env_vals += [env_copy(lv.val, ty, lv.kind)];
310+
}
311+
capture::cap_move. {
312+
env_vals += [env_move(lv.val, ty, lv.kind)];
313+
}
314+
capture::cap_drop. {
315+
bcx = drop_ty(bcx, lv.val, ty);
316+
}
278317
}
279-
env_vals += [env_direct(lv.val, ty, lv.kind == owned)];
280318
}
281-
ret store_environment(cx, copy cx.fcx.lltydescs, env_vals, ck);
319+
ret store_environment(bcx, copy bcx.fcx.lltydescs, env_vals, ck);
282320
}
283321

284322
// Given an enclosing block context, a new function context, a closure type,
@@ -287,7 +325,7 @@ fn build_closure(cx: @block_ctxt,
287325
fn load_environment(enclosing_cx: @block_ctxt,
288326
fcx: @fn_ctxt,
289327
boxed_closure_ty: ty::t,
290-
upvars: freevar_info,
328+
cap_vars: [capture::capture_var],
291329
ck: ty::closure_kind) {
292330
let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
293331

@@ -311,23 +349,34 @@ fn load_environment(enclosing_cx: @block_ctxt,
311349

312350
// Populate the upvars from the environment.
313351
let path = [0, abi::box_rc_field_body, abi::closure_elt_bindings];
314-
vec::iteri(*upvars) { |i, upvar|
315-
check type_is_tup_like(bcx, boxed_closure_ty);
316-
let upvarptr =
317-
GEP_tup_like(bcx, boxed_closure_ty, llclosure, path + [i as int]);
318-
bcx = upvarptr.bcx;
319-
let llupvarptr = upvarptr.val;
320-
alt ck {
321-
ty::closure_block. { llupvarptr = Load(bcx, llupvarptr); }
322-
ty::closure_send. | ty::closure_shared. { }
352+
let i = 0u;
353+
vec::iter(cap_vars) { |cap_var|
354+
alt cap_var.mode {
355+
capture::cap_drop. { /* ignore */ }
356+
_ {
357+
check type_is_tup_like(bcx, boxed_closure_ty);
358+
let upvarptr = GEP_tup_like(
359+
bcx, boxed_closure_ty, llclosure, path + [i as int]);
360+
bcx = upvarptr.bcx;
361+
let llupvarptr = upvarptr.val;
362+
alt ck {
363+
ty::closure_block. { llupvarptr = Load(bcx, llupvarptr); }
364+
ty::closure_send. | ty::closure_shared. { }
365+
}
366+
let def_id = ast_util::def_id_of_def(cap_var.def);
367+
fcx.llupvars.insert(def_id.node, llupvarptr);
368+
i += 1u;
369+
}
323370
}
324-
let def_id = ast_util::def_id_of_def(upvar.def);
325-
fcx.llupvars.insert(def_id.node, llupvarptr);
326371
}
327372
}
328373

329-
fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
330-
id: ast::node_id, dest: dest) -> @block_ctxt {
374+
fn trans_expr_fn(bcx: @block_ctxt,
375+
f: ast::_fn,
376+
sp: span,
377+
id: ast::node_id,
378+
cap_clause: ast::capture_clause,
379+
dest: dest) -> @block_ctxt {
331380
if dest == ignore { ret bcx; }
332381
let ccx = bcx_ccx(bcx), bcx = bcx;
333382
let fty = node_id_type(ccx, id);
@@ -339,10 +388,11 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
339388
register_fn(ccx, sp, sub_cx.path, "anon fn", [], id);
340389

341390
let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
342-
let upvars = get_freevars(ccx.tcx, id);
343-
let {llbox, box_ty, bcx} = build_closure(bcx, upvars, ck);
391+
let cap_vars = capture::compute_capture_vars(
392+
ccx.tcx, id, f.proto, cap_clause);
393+
let {llbox, box_ty, bcx} = build_closure(bcx, cap_vars, ck);
344394
trans_closure(sub_cx, sp, f, llfn, no_self, [], id, {|fcx|
345-
load_environment(bcx, fcx, box_ty, upvars, ck);
395+
load_environment(bcx, fcx, box_ty, cap_vars, ck);
346396
});
347397
llbox
348398
};
@@ -420,7 +470,7 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
420470
let sp = cx.sp;
421471
let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
422472
let src_loc = PointerCast(bcx, cl, llclosurety);
423-
([env_direct(src_loc, pair_ty, true)], none)
473+
([env_copy(src_loc, pair_ty, owned)], none)
424474
}
425475
none. { ([], some(f_res.val)) }
426476
};

trunk/src/comp/middle/tstate/pre_post_conditions.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
347347
handle_var_def(fcx, rslt, def.def, "upvar");
348348
}
349349

350+
let use_cap_item = lambda(&&cap_item: @capture_item) {
351+
let d = local_node_id_to_local_def_id(fcx, cap_item.id);
352+
option::may(d, { |id| use_var(fcx, id) });
353+
};
354+
vec::iter(cap_clause.copies, use_cap_item);
355+
vec::iter(cap_clause.moves, use_cap_item);
356+
350357
vec::iter(cap_clause.moves) { |cap_item|
351358
log ("forget_in_postcond: ", cap_item);
352359
forget_in_postcond(fcx, e.id, cap_item.id);

0 commit comments

Comments
 (0)