librustc: Implement moves based on type. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-12-04 15:38:04 -08:00
parent f02e9db212
commit 33c1e47c1b
19 changed files with 363 additions and 47 deletions

View File

@ -150,8 +150,8 @@ pub pure fn or<T>(opta: Option<T>, optb: Option<T>) -> Option<T> {
/*!
* 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
}
}

View File

@ -1029,9 +1029,9 @@ impl<T: Send> Port<T>: Recv<T> {
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

View File

@ -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));

View File

@ -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;

View File

@ -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));

View File

@ -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 {

View File

@ -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);

181
src/librustc/middle/mode.rs Normal file
View File

@ -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<node_id,method_map_entry>,
mode: ValueMode,
}
fn compute_modes_for_fn_args(callee_id: node_id,
args: &[@expr],
&&cx: VisitContext,
v: vt<VisitContext>) {
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<VisitContext>) {
// 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);
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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<ast::node_id>)
-> 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<ast::node_id, local_val>,
nid: ast::node_id) -> Datum {
nid: ast::node_id,
expr_id_opt: Option<ast::node_id>) -> 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<R>(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<ast::node_id>)
-> 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);
}
}

View File

@ -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<Attribute>) {
let mut cast = false;
let mut ty_attr = option::None;

View File

@ -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<ast::def_id, ast::def_id>,
// A method will be in this list if and only if it is a destructor.
destructors: HashMap<ast::def_id, ()>
destructors: HashMap<ast::def_id, ()>,
// Records the value mode (read, copy, or move) for every value.
value_modes: HashMap<ast::node_id, ValueMode>,
};
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 {

View File

@ -181,6 +181,8 @@ mod middle {
#[legacy_exports]
#[path = "middle/privacy.rs"]
mod privacy;
#[path = "middle/mode.rs"]
mod mode;
}
mod front {

View File

@ -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
};

View File

@ -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
}
}

View File

@ -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;
}

View File

@ -0,0 +1,6 @@
fn main() {
let x = ~"Hello!";
let _y = x;
io::println(x); //~ ERROR use of moved variable
}

View File

@ -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();
}