From 33c1e47c1b09216e100951ba9e95a3c0c61c0cc7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 4 Dec 2012 15:38:04 -0800 Subject: [PATCH] librustc: Implement moves based on type. r=nmatsakis --- src/libcore/option.rs | 4 +- src/libcore/pipes.rs | 6 +- src/librustc/driver/driver.rs | 3 + src/librustc/metadata/common.rs | 3 +- src/librustc/middle/astencode.rs | 12 ++ src/librustc/middle/kind.rs | 13 +- src/librustc/middle/liveness.rs | 17 ++ src/librustc/middle/mode.rs | 181 ++++++++++++++++++ src/librustc/middle/trans/closure.rs | 2 +- src/librustc/middle/trans/datum.rs | 8 +- src/librustc/middle/trans/expr.rs | 69 +++++-- src/librustc/middle/trans/foreign.rs | 26 +-- src/librustc/middle/ty.rs | 24 ++- src/librustc/rustc.rc | 2 + src/libstd/net_tcp.rs | 6 +- src/libsyntax/ext/tt/macro_parser.rs | 4 +- src/test/auxiliary/moves_based_on_type_lib.rs | 15 ++ .../use-after-move-based-on-type.rs | 6 + .../moves-based-on-type-cross-crate.rs | 9 + 19 files changed, 363 insertions(+), 47 deletions(-) create mode 100644 src/librustc/middle/mode.rs create mode 100644 src/test/auxiliary/moves_based_on_type_lib.rs create mode 100644 src/test/compile-fail/use-after-move-based-on-type.rs create mode 100644 src/test/run-pass/moves-based-on-type-cross-crate.rs diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 1da3f1b5dd6..09e35b1037b 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -150,8 +150,8 @@ pub pure fn or(opta: Option, optb: Option) -> Option { /*! * Returns the leftmost some() value, or none if both are none. */ - match opta { - Some(_) => move opta, + match move opta { + Some(move opta) => Some(move opta), _ => move optb } } diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 10f69a9ecaf..ec204ca6736 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -1029,9 +1029,9 @@ impl Port: Recv { pure fn peek() -> bool unsafe { let mut endp = None; endp <-> self.endp; - let peek = match endp { - Some(ref endp) => pipes::peek(endp), - None => fail ~"peeking empty stream" + let peek = match &endp { + &Some(ref endp) => pipes::peek(endp), + &None => fail ~"peeking empty stream" }; self.endp <-> endp; peek diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index a131386ba16..ccc7b1508e7 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -251,6 +251,9 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg, time(time_passes, ~"alt checking", || middle::check_alt::check_crate(ty_cx, crate)); + time(time_passes, ~"mode computation", || + middle::mode::compute_modes(ty_cx, method_map, crate)); + let last_use_map = time(time_passes, ~"liveness checking", || middle::liveness::check_crate(ty_cx, method_map, crate)); diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 48c621ea7d3..0584886e6a0 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -131,7 +131,8 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f tag_table_method_map = 0x60, tag_table_vtable_map = 0x61, tag_table_adjustments = 0x62, - tag_table_legacy_boxed_trait = 0x63 + tag_table_legacy_boxed_trait = 0x63, + tag_table_value_mode = 0x64 } const tag_item_trait_method_sort: uint = 0x70; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 87d7710a289..e3b451219fc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -856,6 +856,15 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, ebml_w.id(id); } } + + do option::iter(&tcx.value_modes.find(id)) |vm| { + do ebml_w.tag(c::tag_table_value_mode) { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) { + (*vm).serialize(&ebml_w) + } + } + } } trait doc_decoder_helpers { @@ -990,6 +999,9 @@ fn decode_side_tables(xcx: extended_decode_ctxt, let adj: @ty::AutoAdjustment = @deserialize(val_dsr); adj.tr(xcx); dcx.tcx.adjustments.insert(id, adj); + } else if tag == (c::tag_table_value_mode as uint) { + let vm: ty::ValueMode = deserialize(val_dsr); + dcx.tcx.value_modes.insert(id, vm); } else { xcx.dcx.tcx.sess.bug( fmt!("unknown tag found in side tables: %x", tag)); diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 443c7286410..cb7aa60cc09 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -12,6 +12,7 @@ use syntax::{visit, ast_util}; use syntax::ast::*; use syntax::codemap::span; use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const}; +use middle::ty::{CopyValue, MoveValue, ReadValue}; use std::map::HashMap; use util::ppaux::{ty_to_str, tys_to_str}; use syntax::print::pprust::expr_to_str; @@ -480,8 +481,16 @@ fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool, // borrowed unique value isn't really a copy !is_autorefd(cx, ex) { - let ty = ty::expr_ty(cx.tcx, ex); - check_copy(cx, ex.id, ty, ex.span, implicit_copy, why); + match cx.tcx.value_modes.find(ex.id) { + None => cx.tcx.sess.span_bug(ex.span, ~"no value mode for lval"), + Some(MoveValue) | Some(ReadValue) => {} // Won't be a copy. + Some(CopyValue) => { + debug!("(kind checking) is a copy value: `%s`", + expr_to_str(ex, cx.tcx.sess.intr())); + let ty = ty::expr_ty(cx.tcx, ex); + check_copy(cx, ex.id, ty, ex.span, implicit_copy, why); + } + } } fn is_autorefd(cx: ctx, ex: @expr) -> bool { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c24c267bc36..636a24f7ed7 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,6 +111,7 @@ use syntax::codemap::span; use syntax::ast::*; use io::WriterUtil; use capture::{cap_move, cap_drop, cap_copy, cap_ref}; +use middle::ty::MoveValue; export check_crate; export last_use_map; @@ -1533,6 +1534,22 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) { for self.variable_from_def_map(expr.id, expr.span).each |var| { let ln = self.live_node(expr.id, expr.span); self.consider_last_use(expr, ln, *var); + + match self.tcx.value_modes.find(expr.id) { + Some(MoveValue) => { + debug!("(checking expr) is a move: `%s`", + expr_to_str(expr, self.tcx.sess.intr())); + self.check_move_from_var(expr.span, ln, *var); + } + Some(v) => { + debug!("(checking expr) not a move (%?): `%s`", + v, + expr_to_str(expr, self.tcx.sess.intr())); + } + None => { + fail ~"no mode for lval"; + } + } } visit::visit_expr(expr, self, vt); diff --git a/src/librustc/middle/mode.rs b/src/librustc/middle/mode.rs new file mode 100644 index 00000000000..b3125077ec2 --- /dev/null +++ b/src/librustc/middle/mode.rs @@ -0,0 +1,181 @@ +use middle::ty; +use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt}; +use middle::typeck::{method_map, method_map_entry}; + +use core::vec; +use std::map::HashMap; +use syntax::ast::{by_copy, by_move, by_ref, by_val, crate, expr, expr_assign}; +use syntax::ast::{expr_addr_of, expr_assign_op, expr_binary, expr_call}; +use syntax::ast::{expr_copy, expr_field, expr_index, expr_method_call}; +use syntax::ast::{expr_path, expr_swap, expr_unary, node_id, sty_uniq}; +use syntax::ast::{sty_value}; +use syntax::ast::{box, uniq, deref, not, neg, expr_paren}; +use syntax::visit; +use syntax::visit::vt; + +struct VisitContext { + tcx: ctxt, + method_map: HashMap, + mode: ValueMode, +} + +fn compute_modes_for_fn_args(callee_id: node_id, + args: &[@expr], + &&cx: VisitContext, + v: vt) { + let arg_tys = ty::ty_fn_args(ty::node_id_to_type(cx.tcx, callee_id)); + for vec::each2(args, arg_tys) |arg, arg_ty| { + match ty::resolved_mode(cx.tcx, arg_ty.mode) { + by_ref => { + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(*arg, arg_cx, v); + } + by_val | by_move | by_copy => compute_modes_for_expr(*arg, cx, v) + } + } +} + +fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) { + match cx.mode { + ReadValue | CopyValue => { + cx.tcx.value_modes.insert(expr.id, cx.mode); + } + MoveValue => { + // This is, contextually, a move, but if this expression + // is implicitly copyable it's cheaper to copy. + let e_ty = ty::expr_ty(cx.tcx, expr); + if ty::type_implicitly_moves(cx.tcx, e_ty) { + cx.tcx.value_modes.insert(expr.id, MoveValue); + } else { + cx.tcx.value_modes.insert(expr.id, CopyValue); + } + } + } +} + +fn compute_modes_for_expr(expr: @expr, + &&cx: VisitContext, + v: vt) { + // Adjust the mode if there was an implicit reference here. + let cx = match cx.tcx.adjustments.find(expr.id) { + None => cx, + Some(adjustment) => { + if adjustment.autoref.is_some() { + VisitContext { mode: ReadValue, ..cx } + } else { + cx + } + } + }; + + match expr.node { + expr_call(callee, args, _) => { + let callee_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(callee, callee_cx, v); + compute_modes_for_fn_args(callee.id, args, cx, v); + } + expr_path(*) => { + record_mode_for_expr(expr, cx); + } + expr_copy(expr) => { + let callee_cx = VisitContext { mode: CopyValue, ..cx }; + compute_modes_for_expr(expr, callee_cx, v); + } + expr_method_call(callee, _, _, args, _) => { + // The LHS of the dot may or may not result in a move, depending + // on the method map entry. + let callee_mode; + match cx.method_map.find(expr.id) { + Some(ref method_map_entry) => { + match method_map_entry.explicit_self { + sty_uniq(_) | sty_value => callee_mode = MoveValue, + _ => callee_mode = ReadValue + } + } + None => { + cx.tcx.sess.span_bug(expr.span, ~"no method map entry"); + } + } + + let callee_cx = VisitContext { mode: callee_mode, ..cx }; + compute_modes_for_expr(callee, callee_cx, v); + + compute_modes_for_fn_args(expr.callee_id, args, cx, v); + } + expr_binary(_, lhs, rhs) | expr_assign_op(_, lhs, rhs) => { + // The signatures of these take their arguments by-ref, so they + // don't copy or move. + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(lhs, arg_cx, v); + compute_modes_for_expr(rhs, arg_cx, v); + } + expr_addr_of(_, arg) => { + // Takes its argument by-ref, so it doesn't copy or move. + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(arg, arg_cx, v); + } + expr_unary(unop, arg) => { + // Ditto. + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(arg, arg_cx, v); + + match unop { + deref => { + // This is an lvalue, so it needs a value mode recorded + // for it. + record_mode_for_expr(expr, cx); + } + box(_) | uniq(_) | not | neg => {} + } + } + expr_field(arg, _, _) => { + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(arg, arg_cx, v); + + record_mode_for_expr(expr, cx); + } + expr_assign(lhs, rhs) => { + // The signatures of these take their arguments by-ref, so they + // don't copy or move. + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(lhs, arg_cx, v); + compute_modes_for_expr(rhs, cx, v); + } + expr_swap(lhs, rhs) => { + let arg_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(lhs, arg_cx, v); + compute_modes_for_expr(rhs, arg_cx, v); + } + expr_index(lhs, rhs) => { + let lhs_cx = VisitContext { mode: ReadValue, ..cx }; + compute_modes_for_expr(lhs, lhs_cx, v); + let rhs_cx = VisitContext { mode: MoveValue, ..cx }; + compute_modes_for_expr(rhs, rhs_cx, v); + + record_mode_for_expr(expr, cx); + } + expr_paren(arg) => { + compute_modes_for_expr(arg, cx, v); + record_mode_for_expr(expr, cx); + } + _ => { + // XXX: Spell out every expression above so when we add them we + // don't forget to update this file. + visit::visit_expr(expr, cx, v) + } + } +} + +pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) { + let visitor = visit::mk_vt(@{ + visit_expr: compute_modes_for_expr, + .. *visit::default_visitor() + }); + let callee_cx = VisitContext { + tcx: tcx, + method_map: method_map, + mode: MoveValue + }; + visit::visit_crate(*crate, callee_cx, visitor); +} + diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 03b46f94a3a..2796cca6838 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -270,7 +270,7 @@ fn build_closure(bcx0: block, let mut env_vals = ~[]; for vec::each(cap_vars) |cap_var| { debug!("Building closure: captured variable %?", *cap_var); - let datum = expr::trans_local_var(bcx, cap_var.def); + let datum = expr::trans_local_var(bcx, cap_var.def, None); match cap_var.mode { capture::cap_ref => { assert proto == ast::ProtoBorrowed; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index fb597cab89a..750efb2ecf7 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -509,13 +509,17 @@ impl Datum { } } - fn GEPi(bcx: block, ixs: &[uint], ty: ty::t) -> Datum { + fn GEPi(bcx: block, + ixs: &[uint], + ty: ty::t, + source: DatumSource) + -> Datum { let base_val = self.to_ref_llval(bcx); Datum { val: GEPi(bcx, base_val, ixs), mode: ByRef, ty: ty, - source: FromLvalue + source: source } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 4e9e1556124..0ea5ded53f4 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -121,6 +121,7 @@ use util::ppaux::ty_to_str; use util::common::indenter; use ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn}; use callee::{AutorefArg, DoAutorefArg, DontAutorefArg}; +use middle::ty::MoveValue; // The primary two functions for translating expressions: export trans_to_datum, trans_into; @@ -736,7 +737,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { return trans_def_lvalue(bcx, expr, bcx.def(expr.id)); } ast::expr_field(base, ident, _) => { - return trans_rec_field(bcx, base, ident); + return trans_rec_field(bcx, base, ident, expr.id); } ast::expr_index(base, idx) => { return trans_index(bcx, expr, base, idx); @@ -756,8 +757,10 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } } -fn trans_def_lvalue(bcx: block, ref_expr: @ast::expr, - def: ast::def) -> DatumBlock { +fn trans_def_lvalue(bcx: block, + ref_expr: @ast::expr, + def: ast::def) + -> DatumBlock { let _icx = bcx.insn_ctxt("trans_def_lvalue"); let ccx = bcx.ccx(); match def { @@ -779,17 +782,21 @@ fn trans_def_lvalue(bcx: block, ref_expr: @ast::expr, _ => { DatumBlock { bcx: bcx, - datum: trans_local_var(bcx, def) + datum: trans_local_var(bcx, def, Some(ref_expr.id)) } } } } -fn trans_local_var(bcx: block, def: ast::def) -> Datum { +fn trans_local_var(bcx: block, + def: ast::def, + expr_id_opt: Option) + -> Datum { let _icx = bcx.insn_ctxt("trans_local_var"); return match def { ast::def_upvar(nid, _, _, _) => { + // Can't move upvars, so this is never a FromLvalueLastUse. let local_ty = node_id_type(bcx, nid); match bcx.fcx.llupvars.find(nid) { Some(val) => { @@ -807,10 +814,10 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum { } } ast::def_arg(nid, _) => { - take_local(bcx, bcx.fcx.llargs, nid) + take_local(bcx, bcx.fcx.llargs, nid, expr_id_opt) } ast::def_local(nid, _) | ast::def_binding(nid, _) => { - take_local(bcx, bcx.fcx.lllocals, nid) + take_local(bcx, bcx.fcx.lllocals, nid, expr_id_opt) } ast::def_self(nid) => { let self_info: ValSelfData = match bcx.fcx.llself { @@ -832,7 +839,7 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum { val: casted_val, ty: self_info.t, mode: ByRef, - source: FromLvalue + source: source_from_opt_lvalue_type(bcx.tcx(), expr_id_opt) } } _ => { @@ -843,8 +850,8 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum { fn take_local(bcx: block, table: HashMap, - nid: ast::node_id) -> Datum { - + nid: ast::node_id, + expr_id_opt: Option) -> Datum { let (v, mode) = match table.find(nid) { Some(local_mem(v)) => (v, ByRef), Some(local_imm(v)) => (v, ByValue), @@ -858,7 +865,12 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum { debug!("take_local(nid=%?, v=%s, mode=%?, ty=%s)", nid, bcx.val_str(v), mode, bcx.ty_to_str(ty)); - Datum { val: v, ty: ty, mode: mode, source: FromLvalue } + Datum { + val: v, + ty: ty, + mode: mode, + source: source_from_opt_lvalue_type(bcx.tcx(), expr_id_opt) + } } } @@ -943,7 +955,8 @@ fn with_field_tys(tcx: ty::ctxt, fn trans_rec_field(bcx: block, base: @ast::expr, - field: ast::ident) -> DatumBlock { + field: ast::ident, + expr_id: ast::node_id) -> DatumBlock { let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_rec_field"); @@ -951,12 +964,30 @@ fn trans_rec_field(bcx: block, do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| { let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys); DatumBlock { - datum: base_datum.GEPi(bcx, [0u, 0u, ix], field_tys[ix].mt.ty), + datum: base_datum.GEPi(bcx, + [0u, 0u, ix], + field_tys[ix].mt.ty, + source_from_opt_lvalue_type( + bcx.tcx(), Some(expr_id))), bcx: bcx } } } +fn source_from_opt_lvalue_type(tcx: ty::ctxt, + expr_id_opt: Option) + -> DatumSource { + match expr_id_opt { + None => FromLvalue, + Some(expr_id) => { + match tcx.value_modes.find(expr_id) { + Some(MoveValue) => FromLastUseLvalue, + Some(_) | None => FromLvalue, + } + } + } +} + fn trans_index(bcx: block, index_expr: @ast::expr, base: @ast::expr, @@ -1010,8 +1041,11 @@ fn trans_index(bcx: block, let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty)); return DatumBlock { bcx: bcx, - datum: Datum {val: elt, ty: vt.unit_ty, - mode: ByRef, source: FromLvalue} + datum: Datum {val: elt, + ty: vt.unit_ty, + mode: ByRef, + source: source_from_opt_lvalue_type( + bcx.tcx(), Some(index_expr.id))} }; } @@ -1101,7 +1135,10 @@ fn trans_rec_or_struct(bcx: block, if !fields.any(|f| f.node.ident == field_ty.ident) { let dest = GEPi(bcx, addr, struct_field(i)); let base_field = - base_datum.GEPi(bcx, struct_field(i), field_ty.mt.ty); + base_datum.GEPi(bcx, + struct_field(i), + field_ty.mt.ty, + FromLvalue); bcx = base_field.store_to(bcx, INIT, dest); } } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index ba9b065901e..adc8500c1ba 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -65,7 +65,7 @@ fn is_sse(++c: x86_64_reg_class) -> bool { }; } -fn is_ymm(cls: ~[x86_64_reg_class]) -> bool { +fn is_ymm(cls: &[x86_64_reg_class]) -> bool { let len = vec::len(cls); return (len > 2u && is_sse(cls[0]) && @@ -136,13 +136,13 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { }; } - fn all_mem(cls: ~[mut x86_64_reg_class]) { + fn all_mem(cls: &[mut x86_64_reg_class]) { for uint::range(0, cls.len()) |i| { cls[i] = memory_class; } } - fn unify(cls: ~[mut x86_64_reg_class], + fn unify(cls: &[mut x86_64_reg_class], i: uint, newv: x86_64_reg_class) { if cls[i] == newv { @@ -167,8 +167,8 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { } } - fn classify_struct(tys: ~[TypeRef], - cls: ~[mut x86_64_reg_class], i: uint, + fn classify_struct(tys: &[TypeRef], + cls: &[mut x86_64_reg_class], i: uint, off: uint) { if vec::is_empty(tys) { classify(T_i64(), cls, i, off); @@ -183,7 +183,7 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { } fn classify(ty: TypeRef, - cls: ~[mut x86_64_reg_class], ix: uint, + cls: &[mut x86_64_reg_class], ix: uint, off: uint) { let t_align = ty_align(ty); let t_size = ty_size(ty); @@ -231,7 +231,7 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { } } - fn fixup(ty: TypeRef, cls: ~[mut x86_64_reg_class]) { + fn fixup(ty: TypeRef, cls: &[mut x86_64_reg_class]) { let mut i = 0u; let llty = llvm::LLVMGetTypeKind(ty) as int; let e = vec::len(cls); @@ -289,8 +289,8 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { return vec::from_mut(move cls); } -fn llreg_ty(cls: ~[x86_64_reg_class]) -> TypeRef { - fn llvec_len(cls: ~[x86_64_reg_class]) -> uint { +fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { + fn llvec_len(cls: &[x86_64_reg_class]) -> uint { let mut len = 1u; for vec::each(cls) |c| { if *c != sseup_class { @@ -342,7 +342,7 @@ type x86_64_tys = { sret: bool }; -fn x86_64_tys(atys: ~[TypeRef], +fn x86_64_tys(atys: &[TypeRef], rty: TypeRef, ret_def: bool) -> x86_64_tys { fn is_reg_ty(ty: TypeRef) -> bool { @@ -355,18 +355,18 @@ fn x86_64_tys(atys: ~[TypeRef], }; } - fn is_pass_byval(cls: ~[x86_64_reg_class]) -> bool { + fn is_pass_byval(cls: &[x86_64_reg_class]) -> bool { return cls[0] == memory_class || cls[0] == x87_class || cls[0] == complex_x87_class; } - fn is_ret_bysret(cls: ~[x86_64_reg_class]) -> bool { + fn is_ret_bysret(cls: &[x86_64_reg_class]) -> bool { return cls[0] == memory_class; } fn x86_64_ty(ty: TypeRef, - is_mem_cls: fn(cls: ~[x86_64_reg_class]) -> bool, + is_mem_cls: fn(cls: &[x86_64_reg_class]) -> bool, attr: Attribute) -> (x86_64_llty, Option) { let mut cast = false; let mut ty_attr = option::None; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d3426a36496..9e002d2d69e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -117,6 +117,7 @@ export ty_uint, mk_uint, mk_mach_uint; export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box; export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var; export InferTy, TyVar, IntVar, FloatVar; +export ValueMode, ReadValue, CopyValue, MoveValue; export ty_self, mk_self, type_has_self; export ty_class; export Region, bound_region, encl_region; @@ -134,6 +135,7 @@ export ty_region; export Kind, kind_implicitly_copyable, kind_send_copy, kind_copyable; export kind_noncopyable, kind_const; export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied; +export type_implicitly_moves; export kind_is_safe_for_default_mode; export kind_is_owned; export meta_kind, kind_lteq, type_kind; @@ -251,6 +253,15 @@ type field_ty = { mutability: ast::class_mutability }; +/// How an lvalue is to be used. +#[auto_serialize] +#[auto_deserialize] +pub enum ValueMode { + ReadValue, // Non-destructively read the value; do not copy or move. + CopyValue, // Copy the value. + MoveValue, // Move the value. +} + // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. type creader_cache_key = {cnum: int, pos: uint, len: uint}; @@ -429,7 +440,10 @@ type ctxt = destructor_for_type: HashMap, // A method will be in this list if and only if it is a destructor. - destructors: HashMap + destructors: HashMap, + + // Records the value mode (read, copy, or move) for every value. + value_modes: HashMap, }; enum tbox_flag { @@ -968,7 +982,8 @@ fn mk_ctxt(s: session::Session, automatically_derived_methods: HashMap(), automatically_derived_methods_for_impl: HashMap(), destructor_for_type: HashMap(), - destructors: HashMap()} + destructors: HashMap(), + value_modes: HashMap()} } @@ -2258,6 +2273,11 @@ fn type_kind(cx: ctxt, ty: t) -> Kind { return result; } +fn type_implicitly_moves(cx: ctxt, ty: t) -> bool { + let kind = type_kind(cx, ty); + !(kind_can_be_copied(kind) && kind_can_be_implicitly_copied(kind)) +} + /// gives a rough estimate of how much space it takes to represent /// an instance of `ty`. Used for the mode transition. fn type_size(cx: ctxt, ty: t) -> uint { diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 01e50f7cf83..543bff8a234 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -181,6 +181,8 @@ mod middle { #[legacy_exports] #[path = "middle/privacy.rs"] mod privacy; + #[path = "middle/mode.rs"] + mod mode; } mod front { diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 9f6c83bb436..4ae2601ebe7 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -610,9 +610,9 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, kill_ch: kill_ch, on_connect_cb: move on_connect_cb, iotask: iotask, - ipv6: match host_ip { - ip::Ipv4(_) => { false } - ip::Ipv6(_) => { true } + ipv6: match &host_ip { + &ip::Ipv4(_) => { false } + &ip::Ipv6(_) => { true } }, mut active: true }; diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index e51800b8a61..e782a183430 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -100,8 +100,8 @@ enum matcher_pos_up { /* to break a circularity */ } fn is_some(&&mpu: matcher_pos_up) -> bool { - match mpu { - matcher_pos_up(None) => false, + match &mpu { + &matcher_pos_up(None) => false, _ => true } } diff --git a/src/test/auxiliary/moves_based_on_type_lib.rs b/src/test/auxiliary/moves_based_on_type_lib.rs new file mode 100644 index 00000000000..b189565bf44 --- /dev/null +++ b/src/test/auxiliary/moves_based_on_type_lib.rs @@ -0,0 +1,15 @@ +#[crate_type="lib"]; + +pub struct S { + x: int, + drop { + io::println("goodbye"); + } +} + +pub fn f() { + let x = S { x: 1 }; + let y = x; + let z = y; +} + diff --git a/src/test/compile-fail/use-after-move-based-on-type.rs b/src/test/compile-fail/use-after-move-based-on-type.rs new file mode 100644 index 00000000000..3d42bf76230 --- /dev/null +++ b/src/test/compile-fail/use-after-move-based-on-type.rs @@ -0,0 +1,6 @@ +fn main() { + let x = ~"Hello!"; + let _y = x; + io::println(x); //~ ERROR use of moved variable +} + diff --git a/src/test/run-pass/moves-based-on-type-cross-crate.rs b/src/test/run-pass/moves-based-on-type-cross-crate.rs new file mode 100644 index 00000000000..08dbd555cd4 --- /dev/null +++ b/src/test/run-pass/moves-based-on-type-cross-crate.rs @@ -0,0 +1,9 @@ +// xfail-fast +// aux-build:moves_based_on_type_lib.rs + +extern mod moves_based_on_type_lib; +use moves_based_on_type_lib::f; + +fn main() { + f(); +}