diff --git a/src/librustc/middle/capture.rs b/src/librustc/middle/capture.rs index bce59a087e903..27b7e30a3d0e8 100644 --- a/src/librustc/middle/capture.rs +++ b/src/librustc/middle/capture.rs @@ -67,6 +67,7 @@ fn check_capture_clause(tcx: ty::ctxt, } fn compute_capture_vars(tcx: ty::ctxt, + span: span, fn_expr_id: ast::node_id, fn_proto: ast::Proto, cap_clause: ast::capture_clause) -> ~[capture_var] { @@ -122,10 +123,26 @@ fn compute_capture_vars(tcx: ty::ctxt, 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 = match implicit_mode { + cap_ref => cap_ref, + cap_copy => { + let fvar_ty = ty::node_id_to_type(tcx, fvar_def_id); + if ty::type_implicitly_moves(tcx, fvar_ty) { + cap_move + } else { + cap_copy + } + } + cap_move | cap_drop => { + tcx.sess.span_bug(span, ~"unexpected cap type") + } + }; + 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 cb7aa60cc0962..476579a0fc7cd 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -200,7 +200,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 }; @@ -214,9 +213,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 e8fcbf123562c..0f744aa86115e 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -523,7 +523,7 @@ 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, + let cvs = capture::compute_capture_vars(self.tcx, expr.span, expr.id, proto, cap_clause); let mut call_caps = ~[]; for cvs.each |cv| { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 81b6778bb398d..e2891a81b7a4b 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -629,7 +629,7 @@ 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, + bcx, arg_expr.span, proto, decl, (*body), blk.id, cap, Some(ret_flag), expr::SaveIn(scratch)); DatumBlock {bcx: bcx, datum: Datum {val: scratch, diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 2796cca68388f..94e8eef7b4d7d 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -370,6 +370,7 @@ fn load_environment(fcx: fn_ctxt, } fn trans_expr_fn(bcx: block, + span: span, proto: ast::Proto, decl: ast::fn_decl, body: ast::blk, @@ -395,7 +396,7 @@ fn trans_expr_fn(bcx: block, let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty); let trans_closure_env = fn@(proto: ast::Proto) -> Result { - let cap_vars = capture::compute_capture_vars(ccx.tcx, id, proto, + let cap_vars = capture::compute_capture_vars(ccx.tcx, span, id, proto, cap_clause); let ret_handle = match is_loop_body { Some(x) => x, None => None }; let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, proto, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 64aed0b283ea9..4a59183d9a3e0 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -548,7 +548,7 @@ 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, + return closure::trans_expr_fn(bcx, expr.span, proto, decl, (*body), expr.id, cap_clause, None, dest); } @@ -560,7 +560,7 @@ 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), + bcx, expr.span, fn_ty.meta.proto, decl, (*body), expr.id, cap_clause, None, dest); } @@ -576,8 +576,8 @@ 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, - cap, Some(None), dest); + bcx, expr.span, fn_ty.meta.proto, decl, + (*body), blk.id, cap, Some(None), dest); } _ => { bcx.sess().impossible_case( diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 04a59d1fe4162..89a87ebd5e853 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -219,6 +219,14 @@ fn mk_pat_enum(cx: ext_ctxt, let pat = ast::pat_enum(path, Some(move subpats)); mk_pat(cx, span, move pat) } +fn mk_pat_struct(cx: ext_ctxt, + span: span, + path: @ast::path, + +field_pats: ~[ast::field_pat]) + -> @ast::pat { + let pat = ast::pat_struct(path, move field_pats, false); + mk_pat(cx, span, move pat) +} fn mk_bool(cx: ext_ctxt, span: span, value: bool) -> @ast::expr { let lit_expr = ast::expr_lit(@{ node: ast::lit_bool(value), span: span }); build::mk_expr(cx, span, move lit_expr) diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index 2aca54446d74e..0f8a1a2322756 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -318,6 +318,26 @@ fn create_iter_bytes_method(cx: ext_ctxt, } } +fn create_subpatterns(cx: ext_ctxt, + span: span, + prefix: ~str, + n: uint) + -> ~[@pat] { + let subpats = dvec::DVec(); + for uint::range(0, n) |_i| { + // Create the subidentifier. + let index = subpats.len().to_str(); + let ident = cx.ident_of(prefix + index); + + // Create the subpattern. + let subpath = build::mk_raw_path(span, ~[ ident ]); + let subpat = pat_ident(bind_by_ref(m_imm), subpath, None); + let subpat = build::mk_pat(cx, span, move subpat); + subpats.push(subpat); + } + return dvec::unwrap(move subpats); +} + fn create_enum_variant_pattern(cx: ext_ctxt, span: span, variant: &variant, @@ -330,25 +350,37 @@ fn create_enum_variant_pattern(cx: ext_ctxt, return build::mk_pat_ident(cx, span, variant_ident); } - let subpats = dvec::DVec(); - for variant_args.each |_variant_arg| { - // Create the subidentifier. - let index = subpats.len().to_str(); - let ident = cx.ident_of(prefix + index); - - // Create the subpattern. - let subpath = build::mk_raw_path(span, ~[ ident ]); - let subpat = pat_ident(bind_by_ref(m_imm), subpath, None); - let subpat = build::mk_pat(cx, span, move subpat); - subpats.push(subpat); - } - let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); - let subpats = dvec::unwrap(move subpats); + let subpats = create_subpatterns(cx, + span, + prefix, + variant_args.len()); + return build::mk_pat_enum(cx, span, matching_path, move subpats); } - struct_variant_kind(*) => { - cx.span_unimpl(span, ~"struct variants for `deriving`"); + struct_variant_kind(struct_def) => { + let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); + let subpats = create_subpatterns(cx, + span, + prefix, + struct_def.fields.len()); + + let field_pats = dvec::DVec(); + for struct_def.fields.eachi |i, struct_field| { + let ident = match struct_field.node.kind { + named_field(ident, _, _) => ident, + unnamed_field => { + cx.span_bug(span, ~"unexpected unnamed field"); + } + }; + field_pats.push({ ident: ident, pat: subpats[i] }); + } + let field_pats = dvec::unwrap(move field_pats); + + return build::mk_pat_struct(cx, + span, + matching_path, + move field_pats); } enum_variant_kind(*) => { cx.span_unimpl(span, ~"enum variants for `deriving`"); 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 0000000000000..26c1e1360e9e1 --- /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/deriving-via-extension-struct-like-enum-variant.rs b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs new file mode 100644 index 0000000000000..c5e41826a3540 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs @@ -0,0 +1,12 @@ +#[deriving_eq] +enum S { + X { x: int, y: int }, + Y +} + +fn main() { + let x = X { x: 1, y: 2 }; + assert x == x; + assert !(x != x); +} + 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 0000000000000..206d45b74fa33 --- /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); + } +} +