diff --git a/src/librustc/middle/capture.rs b/src/librustc/middle/capture.rs index bce59a087e90..f9a7459c6717 100644 --- a/src/librustc/middle/capture.rs +++ b/src/librustc/middle/capture.rs @@ -110,22 +110,29 @@ fn compute_capture_vars(tcx: ty::ctxt, // now go through anything that is referenced but was not explicitly // named and add that - let implicit_mode; - if fn_proto == ast::ProtoBorrowed { - implicit_mode = cap_ref; - } else { - implicit_mode = cap_copy; - } - + let implicit_mode_is_by_ref = fn_proto == ast::ProtoBorrowed; for vec::each(*freevars) |fvar| { let fvar_def_id = ast_util::def_id_of_def(fvar.def).node; match cap_map.find(fvar_def_id) { option::Some(_) => { /* was explicitly named, do nothing */ } option::None => { + // Move if this type implicitly moves; copy otherwise. + let mode; + if implicit_mode_is_by_ref { + mode = cap_ref; + } else { + let fvar_ty = ty::node_id_to_type(tcx, fvar_def_id); + if ty::type_implicitly_moves(tcx, fvar_ty) { + mode = cap_move; + } else { + mode = cap_copy; + } + }; + cap_map.insert(fvar_def_id, {def:fvar.def, span: fvar.span, cap_item: None, - mode:implicit_mode}); + mode:mode}); } } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index a8395013958e..8075fdfe65e4 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -201,7 +201,6 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, let cap_def = cx.tcx.def_map.get(cap_item.id); let cap_def_id = ast_util::def_id_of_def(cap_def).node; let ty = ty::node_id_to_type(cx.tcx, cap_def_id); - // Here's where is_move isn't always false... chk(cx, fn_id, None, cap_item.is_move, ty, cap_item.span); cap_def_id }; @@ -215,9 +214,12 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, if captured_vars.contains(&id) { loop; } let ty = ty::node_id_to_type(cx.tcx, id); - // is_move is always false here. See the let captured_vars... - // code above for where it's not always false. - chk(cx, fn_id, Some(*fv), false, ty, fv.span); + + // is_move is true if this type implicitly moves and false + // otherwise. + let is_move = ty::type_implicitly_moves(cx.tcx, ty); + + chk(cx, fn_id, Some(*fv), is_move, ty, fv.span); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 48fff1a269bd..47284c1df5ac 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -524,8 +524,8 @@ fn visit_expr(expr: @expr, &&self: @IrMaps, vt: vt<@IrMaps>) { // in better error messages than just pointing at the closure // construction site. let proto = ty::ty_fn_proto(ty::expr_ty(self.tcx, expr)); - let cvs = capture::compute_capture_vars(self.tcx, expr.id, - proto, cap_clause); + let cvs = capture::compute_capture_vars(self.tcx, expr.id, proto, + cap_clause); let mut call_caps = ~[]; for cvs.each |cv| { match relevant_def(cv.def) { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 7117ae6910cc..f9694b0ced6e 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -621,8 +621,8 @@ fn trans_arg_expr(bcx: block, let arg_ty = expr_ty(bcx, arg_expr); let proto = ty::ty_fn_proto(arg_ty); let bcx = closure::trans_expr_fn( - bcx, proto, decl, (*body), blk.id, - cap, Some(ret_flag), expr::SaveIn(scratch)); + bcx, proto, decl, (*body), blk.id, cap, + Some(ret_flag), expr::SaveIn(scratch)); DatumBlock {bcx: bcx, datum: Datum {val: scratch, ty: scratch_ty, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 764ddabd1434..d7a1b14fae3e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -549,9 +549,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, ast::expr_fn(proto, decl, ref body, cap_clause) => { // Don't use this function for anything real. Use the one in // astconv instead. - return closure::trans_expr_fn(bcx, proto, - decl, (*body), expr.id, cap_clause, - None, dest); + return closure::trans_expr_fn(bcx, proto, decl, *body, expr.id, + cap_clause, None, dest); } ast::expr_fn_block(decl, ref body, cap_clause) => { let expr_ty = expr_ty(bcx, expr); @@ -561,9 +560,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, expr_to_str(expr, tcx.sess.intr()), ty_to_str(tcx, expr_ty)); return closure::trans_expr_fn( - bcx, fn_ty.meta.proto, decl, (*body), - expr.id, cap_clause, None, - dest); + bcx, fn_ty.meta.proto, decl, *body, expr.id, + cap_clause, None, dest); } _ => { bcx.sess().impossible_case( @@ -577,7 +575,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, match blk.node { ast::expr_fn_block(decl, ref body, cap) => { return closure::trans_expr_fn( - bcx, fn_ty.meta.proto, decl, (*body), blk.id, + bcx, fn_ty.meta.proto, decl, *body, blk.id, cap, Some(None), dest); } _ => { diff --git a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs new file mode 100644 index 000000000000..26c1e1360e9e --- /dev/null +++ b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs @@ -0,0 +1,8 @@ +fn main() { + let x = ~"Hello world!"; + do task::spawn { + io::println(x); + } + io::println(x); //~ ERROR use of moved variable +} + diff --git a/src/test/run-pass/moves-based-on-type-capture-clause.rs b/src/test/run-pass/moves-based-on-type-capture-clause.rs new file mode 100644 index 000000000000..206d45b74fa3 --- /dev/null +++ b/src/test/run-pass/moves-based-on-type-capture-clause.rs @@ -0,0 +1,7 @@ +fn main() { + let x = ~"Hello world!"; + do task::spawn { + io::println(x); + } +} +