librustc: Implement moves based on type. r=nmatsakis
This commit is contained in:
parent
f02e9db212
commit
33c1e47c1b
19 changed files with 363 additions and 47 deletions
|
@ -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.
|
* Returns the leftmost some() value, or none if both are none.
|
||||||
*/
|
*/
|
||||||
match opta {
|
match move opta {
|
||||||
Some(_) => move opta,
|
Some(move opta) => Some(move opta),
|
||||||
_ => move optb
|
_ => move optb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1029,9 +1029,9 @@ impl<T: Send> Port<T>: Recv<T> {
|
||||||
pure fn peek() -> bool unsafe {
|
pure fn peek() -> bool unsafe {
|
||||||
let mut endp = None;
|
let mut endp = None;
|
||||||
endp <-> self.endp;
|
endp <-> self.endp;
|
||||||
let peek = match endp {
|
let peek = match &endp {
|
||||||
Some(ref endp) => pipes::peek(endp),
|
&Some(ref endp) => pipes::peek(endp),
|
||||||
None => fail ~"peeking empty stream"
|
&None => fail ~"peeking empty stream"
|
||||||
};
|
};
|
||||||
self.endp <-> endp;
|
self.endp <-> endp;
|
||||||
peek
|
peek
|
||||||
|
|
|
@ -251,6 +251,9 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg,
|
||||||
time(time_passes, ~"alt checking", ||
|
time(time_passes, ~"alt checking", ||
|
||||||
middle::check_alt::check_crate(ty_cx, crate));
|
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 =
|
let last_use_map =
|
||||||
time(time_passes, ~"liveness checking", ||
|
time(time_passes, ~"liveness checking", ||
|
||||||
middle::liveness::check_crate(ty_cx, method_map, crate));
|
middle::liveness::check_crate(ty_cx, method_map, crate));
|
||||||
|
|
|
@ -131,7 +131,8 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f
|
||||||
tag_table_method_map = 0x60,
|
tag_table_method_map = 0x60,
|
||||||
tag_table_vtable_map = 0x61,
|
tag_table_vtable_map = 0x61,
|
||||||
tag_table_adjustments = 0x62,
|
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;
|
const tag_item_trait_method_sort: uint = 0x70;
|
||||||
|
|
|
@ -856,6 +856,15 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
|
||||||
ebml_w.id(id);
|
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 {
|
trait doc_decoder_helpers {
|
||||||
|
@ -990,6 +999,9 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
|
||||||
let adj: @ty::AutoAdjustment = @deserialize(val_dsr);
|
let adj: @ty::AutoAdjustment = @deserialize(val_dsr);
|
||||||
adj.tr(xcx);
|
adj.tr(xcx);
|
||||||
dcx.tcx.adjustments.insert(id, adj);
|
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 {
|
} else {
|
||||||
xcx.dcx.tcx.sess.bug(
|
xcx.dcx.tcx.sess.bug(
|
||||||
fmt!("unknown tag found in side tables: %x", tag));
|
fmt!("unknown tag found in side tables: %x", tag));
|
||||||
|
|
|
@ -12,6 +12,7 @@ use syntax::{visit, ast_util};
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use syntax::codemap::span;
|
use syntax::codemap::span;
|
||||||
use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const};
|
use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const};
|
||||||
|
use middle::ty::{CopyValue, MoveValue, ReadValue};
|
||||||
use std::map::HashMap;
|
use std::map::HashMap;
|
||||||
use util::ppaux::{ty_to_str, tys_to_str};
|
use util::ppaux::{ty_to_str, tys_to_str};
|
||||||
use syntax::print::pprust::expr_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
|
// borrowed unique value isn't really a copy
|
||||||
!is_autorefd(cx, ex)
|
!is_autorefd(cx, ex)
|
||||||
{
|
{
|
||||||
let ty = ty::expr_ty(cx.tcx, ex);
|
match cx.tcx.value_modes.find(ex.id) {
|
||||||
check_copy(cx, ex.id, ty, ex.span, implicit_copy, why);
|
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 {
|
fn is_autorefd(cx: ctx, ex: @expr) -> bool {
|
||||||
|
|
|
@ -111,6 +111,7 @@ use syntax::codemap::span;
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use io::WriterUtil;
|
use io::WriterUtil;
|
||||||
use capture::{cap_move, cap_drop, cap_copy, cap_ref};
|
use capture::{cap_move, cap_drop, cap_copy, cap_ref};
|
||||||
|
use middle::ty::MoveValue;
|
||||||
|
|
||||||
export check_crate;
|
export check_crate;
|
||||||
export last_use_map;
|
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| {
|
for self.variable_from_def_map(expr.id, expr.span).each |var| {
|
||||||
let ln = self.live_node(expr.id, expr.span);
|
let ln = self.live_node(expr.id, expr.span);
|
||||||
self.consider_last_use(expr, ln, *var);
|
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);
|
visit::visit_expr(expr, self, vt);
|
||||||
|
|
181
src/librustc/middle/mode.rs
Normal file
181
src/librustc/middle/mode.rs
Normal 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);
|
||||||
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ fn build_closure(bcx0: block,
|
||||||
let mut env_vals = ~[];
|
let mut env_vals = ~[];
|
||||||
for vec::each(cap_vars) |cap_var| {
|
for vec::each(cap_vars) |cap_var| {
|
||||||
debug!("Building closure: captured variable %?", *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 {
|
match cap_var.mode {
|
||||||
capture::cap_ref => {
|
capture::cap_ref => {
|
||||||
assert proto == ast::ProtoBorrowed;
|
assert proto == ast::ProtoBorrowed;
|
||||||
|
|
|
@ -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);
|
let base_val = self.to_ref_llval(bcx);
|
||||||
Datum {
|
Datum {
|
||||||
val: GEPi(bcx, base_val, ixs),
|
val: GEPi(bcx, base_val, ixs),
|
||||||
mode: ByRef,
|
mode: ByRef,
|
||||||
ty: ty,
|
ty: ty,
|
||||||
source: FromLvalue
|
source: source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ use util::ppaux::ty_to_str;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
|
use ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
|
||||||
use callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
|
use callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
|
||||||
|
use middle::ty::MoveValue;
|
||||||
|
|
||||||
// The primary two functions for translating expressions:
|
// The primary two functions for translating expressions:
|
||||||
export trans_to_datum, trans_into;
|
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));
|
return trans_def_lvalue(bcx, expr, bcx.def(expr.id));
|
||||||
}
|
}
|
||||||
ast::expr_field(base, ident, _) => {
|
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) => {
|
ast::expr_index(base, idx) => {
|
||||||
return trans_index(bcx, expr, 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,
|
fn trans_def_lvalue(bcx: block,
|
||||||
def: ast::def) -> DatumBlock {
|
ref_expr: @ast::expr,
|
||||||
|
def: ast::def)
|
||||||
|
-> DatumBlock {
|
||||||
let _icx = bcx.insn_ctxt("trans_def_lvalue");
|
let _icx = bcx.insn_ctxt("trans_def_lvalue");
|
||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
match def {
|
match def {
|
||||||
|
@ -779,17 +782,21 @@ fn trans_def_lvalue(bcx: block, ref_expr: @ast::expr,
|
||||||
_ => {
|
_ => {
|
||||||
DatumBlock {
|
DatumBlock {
|
||||||
bcx: bcx,
|
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");
|
let _icx = bcx.insn_ctxt("trans_local_var");
|
||||||
|
|
||||||
return match def {
|
return match def {
|
||||||
ast::def_upvar(nid, _, _, _) => {
|
ast::def_upvar(nid, _, _, _) => {
|
||||||
|
// Can't move upvars, so this is never a FromLvalueLastUse.
|
||||||
let local_ty = node_id_type(bcx, nid);
|
let local_ty = node_id_type(bcx, nid);
|
||||||
match bcx.fcx.llupvars.find(nid) {
|
match bcx.fcx.llupvars.find(nid) {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
|
@ -807,10 +814,10 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::def_arg(nid, _) => {
|
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, _) => {
|
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) => {
|
ast::def_self(nid) => {
|
||||||
let self_info: ValSelfData = match bcx.fcx.llself {
|
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,
|
val: casted_val,
|
||||||
ty: self_info.t,
|
ty: self_info.t,
|
||||||
mode: ByRef,
|
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,
|
fn take_local(bcx: block,
|
||||||
table: HashMap<ast::node_id, local_val>,
|
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) {
|
let (v, mode) = match table.find(nid) {
|
||||||
Some(local_mem(v)) => (v, ByRef),
|
Some(local_mem(v)) => (v, ByRef),
|
||||||
Some(local_imm(v)) => (v, ByValue),
|
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)",
|
debug!("take_local(nid=%?, v=%s, mode=%?, ty=%s)",
|
||||||
nid, bcx.val_str(v), mode, bcx.ty_to_str(ty));
|
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,
|
fn trans_rec_field(bcx: block,
|
||||||
base: @ast::expr,
|
base: @ast::expr,
|
||||||
field: ast::ident) -> DatumBlock {
|
field: ast::ident,
|
||||||
|
expr_id: ast::node_id) -> DatumBlock {
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let _icx = bcx.insn_ctxt("trans_rec_field");
|
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| {
|
do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| {
|
||||||
let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
|
let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
|
||||||
DatumBlock {
|
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
|
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,
|
fn trans_index(bcx: block,
|
||||||
index_expr: @ast::expr,
|
index_expr: @ast::expr,
|
||||||
base: @ast::expr,
|
base: @ast::expr,
|
||||||
|
@ -1010,8 +1041,11 @@ fn trans_index(bcx: block,
|
||||||
let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
|
let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
|
||||||
return DatumBlock {
|
return DatumBlock {
|
||||||
bcx: bcx,
|
bcx: bcx,
|
||||||
datum: Datum {val: elt, ty: vt.unit_ty,
|
datum: Datum {val: elt,
|
||||||
mode: ByRef, source: FromLvalue}
|
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) {
|
if !fields.any(|f| f.node.ident == field_ty.ident) {
|
||||||
let dest = GEPi(bcx, addr, struct_field(i));
|
let dest = GEPi(bcx, addr, struct_field(i));
|
||||||
let base_field =
|
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);
|
bcx = base_field.store_to(bcx, INIT, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
let len = vec::len(cls);
|
||||||
return (len > 2u &&
|
return (len > 2u &&
|
||||||
is_sse(cls[0]) &&
|
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| {
|
for uint::range(0, cls.len()) |i| {
|
||||||
cls[i] = memory_class;
|
cls[i] = memory_class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(cls: ~[mut x86_64_reg_class],
|
fn unify(cls: &[mut x86_64_reg_class],
|
||||||
i: uint,
|
i: uint,
|
||||||
newv: x86_64_reg_class) {
|
newv: x86_64_reg_class) {
|
||||||
if cls[i] == newv {
|
if cls[i] == newv {
|
||||||
|
@ -167,8 +167,8 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_struct(tys: ~[TypeRef],
|
fn classify_struct(tys: &[TypeRef],
|
||||||
cls: ~[mut x86_64_reg_class], i: uint,
|
cls: &[mut x86_64_reg_class], i: uint,
|
||||||
off: uint) {
|
off: uint) {
|
||||||
if vec::is_empty(tys) {
|
if vec::is_empty(tys) {
|
||||||
classify(T_i64(), cls, i, off);
|
classify(T_i64(), cls, i, off);
|
||||||
|
@ -183,7 +183,7 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify(ty: TypeRef,
|
fn classify(ty: TypeRef,
|
||||||
cls: ~[mut x86_64_reg_class], ix: uint,
|
cls: &[mut x86_64_reg_class], ix: uint,
|
||||||
off: uint) {
|
off: uint) {
|
||||||
let t_align = ty_align(ty);
|
let t_align = ty_align(ty);
|
||||||
let t_size = ty_size(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 mut i = 0u;
|
||||||
let llty = llvm::LLVMGetTypeKind(ty) as int;
|
let llty = llvm::LLVMGetTypeKind(ty) as int;
|
||||||
let e = vec::len(cls);
|
let e = vec::len(cls);
|
||||||
|
@ -289,8 +289,8 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
|
||||||
return vec::from_mut(move cls);
|
return vec::from_mut(move cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn llreg_ty(cls: ~[x86_64_reg_class]) -> TypeRef {
|
fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef {
|
||||||
fn llvec_len(cls: ~[x86_64_reg_class]) -> uint {
|
fn llvec_len(cls: &[x86_64_reg_class]) -> uint {
|
||||||
let mut len = 1u;
|
let mut len = 1u;
|
||||||
for vec::each(cls) |c| {
|
for vec::each(cls) |c| {
|
||||||
if *c != sseup_class {
|
if *c != sseup_class {
|
||||||
|
@ -342,7 +342,7 @@ type x86_64_tys = {
|
||||||
sret: bool
|
sret: bool
|
||||||
};
|
};
|
||||||
|
|
||||||
fn x86_64_tys(atys: ~[TypeRef],
|
fn x86_64_tys(atys: &[TypeRef],
|
||||||
rty: TypeRef,
|
rty: TypeRef,
|
||||||
ret_def: bool) -> x86_64_tys {
|
ret_def: bool) -> x86_64_tys {
|
||||||
fn is_reg_ty(ty: TypeRef) -> bool {
|
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 ||
|
return cls[0] == memory_class ||
|
||||||
cls[0] == x87_class ||
|
cls[0] == x87_class ||
|
||||||
cls[0] == complex_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;
|
return cls[0] == memory_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn x86_64_ty(ty: TypeRef,
|
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>) {
|
attr: Attribute) -> (x86_64_llty, Option<Attribute>) {
|
||||||
let mut cast = false;
|
let mut cast = false;
|
||||||
let mut ty_attr = option::None;
|
let mut ty_attr = option::None;
|
||||||
|
|
|
@ -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_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 ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var;
|
||||||
export InferTy, TyVar, IntVar, FloatVar;
|
export InferTy, TyVar, IntVar, FloatVar;
|
||||||
|
export ValueMode, ReadValue, CopyValue, MoveValue;
|
||||||
export ty_self, mk_self, type_has_self;
|
export ty_self, mk_self, type_has_self;
|
||||||
export ty_class;
|
export ty_class;
|
||||||
export Region, bound_region, encl_region;
|
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, kind_implicitly_copyable, kind_send_copy, kind_copyable;
|
||||||
export kind_noncopyable, kind_const;
|
export kind_noncopyable, kind_const;
|
||||||
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
|
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_safe_for_default_mode;
|
||||||
export kind_is_owned;
|
export kind_is_owned;
|
||||||
export meta_kind, kind_lteq, type_kind;
|
export meta_kind, kind_lteq, type_kind;
|
||||||
|
@ -251,6 +253,15 @@ type field_ty = {
|
||||||
mutability: ast::class_mutability
|
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
|
// Contains information needed to resolve types and (in the future) look up
|
||||||
// the types of AST nodes.
|
// the types of AST nodes.
|
||||||
type creader_cache_key = {cnum: int, pos: uint, len: uint};
|
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>,
|
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.
|
// 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 {
|
enum tbox_flag {
|
||||||
|
@ -968,7 +982,8 @@ fn mk_ctxt(s: session::Session,
|
||||||
automatically_derived_methods: HashMap(),
|
automatically_derived_methods: HashMap(),
|
||||||
automatically_derived_methods_for_impl: HashMap(),
|
automatically_derived_methods_for_impl: HashMap(),
|
||||||
destructor_for_type: 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;
|
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
|
/// gives a rough estimate of how much space it takes to represent
|
||||||
/// an instance of `ty`. Used for the mode transition.
|
/// an instance of `ty`. Used for the mode transition.
|
||||||
fn type_size(cx: ctxt, ty: t) -> uint {
|
fn type_size(cx: ctxt, ty: t) -> uint {
|
||||||
|
|
|
@ -181,6 +181,8 @@ mod middle {
|
||||||
#[legacy_exports]
|
#[legacy_exports]
|
||||||
#[path = "middle/privacy.rs"]
|
#[path = "middle/privacy.rs"]
|
||||||
mod privacy;
|
mod privacy;
|
||||||
|
#[path = "middle/mode.rs"]
|
||||||
|
mod mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod front {
|
mod front {
|
||||||
|
|
|
@ -610,9 +610,9 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint,
|
||||||
kill_ch: kill_ch,
|
kill_ch: kill_ch,
|
||||||
on_connect_cb: move on_connect_cb,
|
on_connect_cb: move on_connect_cb,
|
||||||
iotask: iotask,
|
iotask: iotask,
|
||||||
ipv6: match host_ip {
|
ipv6: match &host_ip {
|
||||||
ip::Ipv4(_) => { false }
|
&ip::Ipv4(_) => { false }
|
||||||
ip::Ipv6(_) => { true }
|
&ip::Ipv6(_) => { true }
|
||||||
},
|
},
|
||||||
mut active: true
|
mut active: true
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,8 +100,8 @@ enum matcher_pos_up { /* to break a circularity */
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_some(&&mpu: matcher_pos_up) -> bool {
|
fn is_some(&&mpu: matcher_pos_up) -> bool {
|
||||||
match mpu {
|
match &mpu {
|
||||||
matcher_pos_up(None) => false,
|
&matcher_pos_up(None) => false,
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/test/auxiliary/moves_based_on_type_lib.rs
Normal file
15
src/test/auxiliary/moves_based_on_type_lib.rs
Normal 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;
|
||||||
|
}
|
||||||
|
|
6
src/test/compile-fail/use-after-move-based-on-type.rs
Normal file
6
src/test/compile-fail/use-after-move-based-on-type.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() {
|
||||||
|
let x = ~"Hello!";
|
||||||
|
let _y = x;
|
||||||
|
io::println(x); //~ ERROR use of moved variable
|
||||||
|
}
|
||||||
|
|
9
src/test/run-pass/moves-based-on-type-cross-crate.rs
Normal file
9
src/test/run-pass/moves-based-on-type-cross-crate.rs
Normal 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();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue