diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-01-09 06:49:56 -0800 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-01-09 06:50:40 -0800 |
| commit | 51364b5708d83aef3bc6371b052e7644efe55121 (patch) | |
| tree | 5c6be46372ff98644b25a865220c09cec4de6478 | |
| parent | 8944a390c64b892b1718b7817a463e4f227f37a8 (diff) | |
| download | rust-51364b5708d83aef3bc6371b052e7644efe55121.tar.gz rust-51364b5708d83aef3bc6371b052e7644efe55121.zip | |
Fix #1474: check that block args resolved to bare fns do not make use of upvars
| -rw-r--r-- | src/comp/middle/kind.rs | 21 | ||||
| -rw-r--r-- | src/test/compile-fail/bad-var-env-capture-in-block-arg.rs | 7 |
2 files changed, 20 insertions, 8 deletions
diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index 00d5534bfec..2e3060b2c2b 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -56,13 +56,14 @@ fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, // Yields the appropriate function to check the kind of closed over // variables. `id` is the node_id for some expression that creates the // closure. -fn with_closure_check_fn(cx: ctx, id: node_id, - b: block(fn(ctx, ty::t, sp: span))) { +fn with_appropriate_checker(cx: ctx, id: node_id, + b: block(fn(ctx, ty::t, sp: span))) { let fty = ty::node_id_to_monotype(cx.tcx, id); alt ty::ty_fn_proto(cx.tcx, fty) { proto_send. { b(check_send); } proto_shared(_) { b(check_copy); } - proto_block. | proto_bare. { /* no check needed */ } + proto_block. { /* no check needed */ } + proto_bare. { b(check_none); } } } @@ -81,11 +82,11 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, // "future-proof" to do it this way, as check_fn_body() is supposed to be // the common flow point for all functions that appear in the AST. - with_closure_check_fn(cx, id) { |check_fn| + with_appropriate_checker(cx, id) { |checker| for @{def, span} in *freevars::get_freevars(cx.tcx, id) { let id = ast_util::def_id_of_def(def).node; let ty = ty::node_id_to_type(cx.tcx, id); - check_fn(cx, ty, span); + checker(cx, ty, span); } } @@ -96,7 +97,7 @@ fn check_fn_cap_clause(cx: ctx, id: node_id, cap_clause: capture_clause) { // Check that the variables named in the clause which are not free vars - // (if any) are also legal. freevars are checked above in check_fn_body. + // (if any) are also legal. freevars are checked above in check_fn(). // This is kind of a degenerate case, as captured variables will generally // appear free in the body. let freevars = freevars::get_freevars(cx.tcx, id); @@ -104,13 +105,13 @@ fn check_fn_cap_clause(cx: ctx, ast_util::def_id_of_def(freevar.def).node }); //log("freevar_ids", freevar_ids); - with_closure_check_fn(cx, id) { |check_fn| + with_appropriate_checker(cx, id) { |checker| let check_var = lambda(&&cap_item: @capture_item) { let cap_def = cx.tcx.def_map.get(cap_item.id); let cap_def_id = ast_util::def_id_of_def(cap_def).node; if !vec::member(cap_def_id, freevar_ids) { let ty = ty::node_id_to_type(cx.tcx, cap_def_id); - check_fn(cx, ty, cap_item.span); + checker(cx, ty, cap_item.span); } }; vec::iter(cap_clause.copies, check_var); @@ -240,6 +241,10 @@ fn check_send(cx: ctx, ty: ty::t, sp: span) { } } +fn check_none(cx: ctx, _ty: ty::t, sp: span) { + cx.tcx.sess.span_err(sp, "attempted dynamic environment capture"); +} + // // Local Variables: // mode: rust diff --git a/src/test/compile-fail/bad-var-env-capture-in-block-arg.rs b/src/test/compile-fail/bad-var-env-capture-in-block-arg.rs new file mode 100644 index 00000000000..4b46d96b590 --- /dev/null +++ b/src/test/compile-fail/bad-var-env-capture-in-block-arg.rs @@ -0,0 +1,7 @@ +fn main() { + let x = 3; + fn blah(_a: fn()) {} + blah({|| + log(debug, x); //! ERROR attempted dynamic environment capture + }); +} \ No newline at end of file |
