// 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});
}
}
}
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
};
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);
}
}
// 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) {
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,
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);
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(
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);
}
_ => {
--- /dev/null
+fn main() {
+ let x = ~"Hello world!";
+ do task::spawn {
+ io::println(x);
+ }
+ io::println(x); //~ ERROR use of moved variable
+}
+
--- /dev/null
+fn main() {
+ let x = ~"Hello world!";
+ do task::spawn {
+ io::println(x);
+ }
+}
+