diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index fa60fa5934a9..76b7cfa76cdd 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -4,8 +4,7 @@ import session::session; import syntax::parse; import syntax::{ast, codemap}; import syntax::attr; -import middle::{trans, resolve, freevars, kind, ty, typeck, - last_use, lint}; +import middle::{trans, resolve, freevars, kind, ty, typeck, lint}; import syntax::print::{pp, pprust}; import util::{ppaux, filesearch}; import back::link; @@ -192,7 +191,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, bind middle::check_loop::check_crate(ty_cx, crate)); time(time_passes, "alt checking", bind middle::check_alt::check_crate(ty_cx, crate)); - let _last_use_map = + let (last_use_map, spill_map) = time(time_passes, "liveness checking", bind middle::liveness::check_crate(ty_cx, method_map, crate)); time(time_passes, "typestate checking", @@ -200,13 +199,11 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let (root_map, mutbl_map) = time( time_passes, "borrow checking", bind middle::borrowck::check_crate(ty_cx, method_map, crate)); - let (copy_map, ref_map) = + let (copy_map, _ref_map) = time(time_passes, "alias checking", bind middle::alias::check_crate(ty_cx, crate)); - let (last_uses, spill_map) = time(time_passes, "last use finding", - bind last_use::find_last_uses(crate, def_map, ref_map, ty_cx)); time(time_passes, "kind checking", - bind kind::check_crate(ty_cx, method_map, last_uses, crate)); + bind kind::check_crate(ty_cx, method_map, last_use_map, crate)); lint::check_crate(ty_cx, crate, sess.opts.lint_opts, time_passes); @@ -214,7 +211,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let outputs = option::get(outputs); let maps = {mutbl_map: mutbl_map, root_map: root_map, - copy_map: copy_map, last_uses: last_uses, + copy_map: copy_map, last_use_map: last_use_map, impl_map: impl_map, method_map: method_map, vtable_map: vtable_map, spill_map: spill_map}; diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 796f316f442f..af19496c9b87 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -1,5 +1,6 @@ import util::ppaux::ty_to_str; +import dvec::extensions; import syntax::ast; import syntax::fold; import syntax::visit; @@ -18,7 +19,7 @@ import std::serialization::serializer_helpers; import std::serialization::deserializer_helpers; import std::prettyprint::serializer; import std::smallintmap::map; -import middle::{ty, typeck, last_use}; +import middle::{ty, typeck}; import middle::typeck::{method_origin, serialize_method_origin, deserialize_method_origin, @@ -52,11 +53,11 @@ type maps = { mutbl_map: middle::borrowck::mutbl_map, root_map: middle::borrowck::root_map, copy_map: middle::alias::copy_map, - last_uses: middle::last_use::last_uses, + last_use_map: middle::liveness::last_use_map, impl_map: middle::resolve::impl_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, - spill_map: middle::last_use::spill_map + spill_map: middle::liveness::spill_map }; type decode_ctxt = @{ @@ -539,10 +540,6 @@ impl helper for ebml::ebml_deserializer { let fv = deserialize_method_origin(self); fv.tr(xcx) } - fn read_is_last_use(xcx: extended_decode_ctxt) -> last_use::is_last_use { - let lu = last_use::deserialize_is_last_use(self); - lu.tr(xcx) - } } impl of tr for method_origin { @@ -561,17 +558,6 @@ impl of tr for method_origin { } } -impl of tr for last_use::is_last_use { - fn tr(xcx: extended_decode_ctxt) -> last_use::is_last_use { - alt self { - last_use::is_last_use { self } - last_use::closes_over(ids) { - last_use::closes_over(vec::map(ids, {|id| xcx.tr_id(id)})) - } - } - } -} - // ______________________________________________________________________ // Encoding and decoding vtable_res @@ -844,11 +830,13 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, } } - option::iter(maps.last_uses.find(id)) {|m| + option::iter(maps.last_use_map.find(id)) {|m| ebml_w.tag(c::tag_table_last_use) {|| ebml_w.id(id); ebml_w.tag(c::tag_table_val) {|| - last_use::serialize_is_last_use(ebml_w, m) + ebml_w.emit_from_vec((*m).get()) {|id| + ebml_w.emit_int(id); + } } } } @@ -975,7 +963,11 @@ fn decode_side_tables(xcx: extended_decode_ctxt, let bounds = val_dsr.read_bounds(xcx); dcx.tcx.ty_param_bounds.insert(id, bounds); } else if tag == (c::tag_table_last_use as uint) { - dcx.maps.last_uses.insert(id, val_dsr.read_is_last_use(xcx)); + let ids = val_dsr.read_to_vec {|| + xcx.tr_id(val_dsr.read_int()) + }; + let dvec = @dvec::from_vec(vec::to_mut(ids)); + dcx.maps.last_use_map.insert(id, dvec); } else if tag == (c::tag_table_method_map as uint) { dcx.maps.method_map.insert(id, val_dsr.read_method_origin(xcx)); diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index 8cf6671a3d45..d6e7ce1b9907 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -138,10 +138,10 @@ enum loan_path { // a complete record of a loan that was granted type loan = {lp: @loan_path, cmt: cmt, mutbl: ast::mutability}; -fn save_and_restore(&t: T, f: fn() -> U) -> U { - let old_t = t; +fn save_and_restore(&save_and_restore_t: T, f: fn() -> U) -> U { + let old_save_and_restore_t = save_and_restore_t; let u <- f(); - t = old_t; + save_and_restore_t = old_save_and_restore_t; ret u; } @@ -888,6 +888,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, sp: span, id: ast::node_id, &&self: check_loan_ctxt, visitor: visit::vt) { + #debug["purity on entry=%?", self.declared_purity]; save_and_restore(self.in_ctor) {|| save_and_restore(self.declared_purity) {|| // In principle, we could consider fk_anon(*) or @@ -909,6 +910,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, visit::visit_fn(fk, decl, body, sp, id, self, visitor); } } + #debug["purity on exit=%?", self.declared_purity]; } fn check_loans_in_expr(expr: @ast::expr, diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 946246390939..cebefa01abcf 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -8,6 +8,7 @@ import std::map::hashmap; import util::ppaux::{ty_to_str, tys_to_str}; import syntax::print::pprust::expr_to_str; import freevars::freevar_entry; +import dvec::extensions; // Kind analysis pass. // @@ -56,15 +57,15 @@ type rval_map = std::map::hashmap; type ctx = {tcx: ty::ctxt, rval_map: rval_map, method_map: typeck::method_map, - last_uses: last_use::last_uses}; + last_use_map: liveness::last_use_map}; fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - last_uses: last_use::last_uses, crate: @crate) + last_use_map: liveness::last_use_map, crate: @crate) -> rval_map { let ctx = {tcx: tcx, rval_map: std::map::int_hash(), method_map: method_map, - last_uses: last_uses}; + last_use_map: last_use_map}; let visit = visit::mk_vt(@{ visit_expr: check_expr, visit_stmt: check_stmt, @@ -177,11 +178,10 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, // if this is the last use of the variable, then it will be // a move and not a copy let is_move = { - let last_uses = alt check cx.last_uses.find(fn_id) { - some(last_use::closes_over(vars)) { vars } - none { [] } - }; - last_uses.contains(id) + alt check cx.last_use_map.find(fn_id) { + some(vars) {(*vars).contains(id)} + none {false} + } }; let ty = ty::node_id_to_type(cx.tcx, id); @@ -367,7 +367,7 @@ fn is_nullary_variant(cx: ctx, ex: @expr) -> bool { fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) { if ty::expr_is_lval(cx.method_map, ex) && - !cx.last_uses.contains_key(ex.id) && + !cx.last_use_map.contains_key(ex.id) && !is_nullary_variant(cx, ex) { let ty = ty::expr_ty(cx.tcx, ex); check_copy(cx, ty, ex.span); diff --git a/src/rustc/middle/last_use.rs b/src/rustc/middle/last_use.rs deleted file mode 100644 index 0c49196a0cde..000000000000 --- a/src/rustc/middle/last_use.rs +++ /dev/null @@ -1,393 +0,0 @@ -import syntax::{visit, ast_util}; -import syntax::ast::*; -import syntax::codemap::span; -import std::list::{is_not_empty, list, nil, cons, tail}; -import core::unreachable; -import std::list; -import std::map::hashmap; - -// Last use analysis pass. -// -// Finds the last read of each value stored in a local variable or -// callee-owned argument (arguments with by-move or by-copy passing -// style). This is a limited form of liveness analysis, peformed -// (perhaps foolishly) directly on the AST. -// -// The algorithm walks the AST, keeping a set of (def, last_use) -// pairs. When the function is exited, or the local is overwritten, -// the current set of last uses is marked with 'true' in a table. -// Other branches may later overwrite them with 'false' again, since -// they may find a use coming after them. (Marking an expression as a -// last use is only done if it has not already been marked with -// 'false'.) -// -// Some complexity is added to deal with joining control flow branches -// (by `break` or conditionals), and for handling loops. - -// Marks expr_paths that are last uses. -#[auto_serialize] -enum is_last_use { - is_last_use, - closes_over([node_id]), -} -type last_uses = std::map::hashmap; -type spill_map = std::map::hashmap; - -enum seen { unset, seen(node_id), } -enum block_type { func, lp, } - -enum use { var_use(node_id), close_over(node_id), } -type set = [{def: node_id, uses: @list}]; -type bl = @{type: block_type, mut second: bool, mut exits: [set]}; - -enum use_id { path(node_id), close(node_id, node_id) } -fn hash_use_id(id: use_id) -> uint { - (alt id { path(i) { i } close(i, j) { (i << 10) + j } }) as uint -} - -type ctx = {last_uses: std::map::hashmap, - spill_map: std::map::hashmap, - def_map: resolve::def_map, - ref_map: alias::ref_map, - tcx: ty::ctxt, - // The current set of local last uses - mut current: set, - mut blocks: @list}; - -fn find_last_uses(c: @crate, def_map: resolve::def_map, - ref_map: alias::ref_map, tcx: ty::ctxt) - -> (last_uses, spill_map) { - let v = visit::mk_vt(@{visit_expr: visit_expr, - visit_stmt: visit_stmt, - visit_fn: visit_fn - with *visit::default_visitor()}); - let cx = {last_uses: std::map::hashmap(hash_use_id, {|a, b| a == b}), - spill_map: std::map::int_hash(), - def_map: def_map, - ref_map: ref_map, - tcx: tcx, - mut current: [], - mut blocks: @nil}; - visit::visit_crate(*c, cx, v); - let mini_table = std::map::int_hash(); - for cx.last_uses.each {|key, val| - if val { - alt key { - path(id) { - mini_table.insert(id, is_last_use); - let def_node = ast_util::def_id_of_def(def_map.get(id)).node; - cx.spill_map.insert(def_node, ()); - } - close(fn_id, local_id) { - cx.spill_map.insert(local_id, ()); - let known = alt check mini_table.find(fn_id) { - some(closes_over(ids)) { ids } - none { [] } - }; - mini_table.insert(fn_id, closes_over(known + [local_id])); - } - } - } - } - ret (mini_table, cx.spill_map); -} - -fn visit_expr(ex: @expr, cx: ctx, v: visit::vt) { - alt ex.node { - expr_ret(oexpr) { - visit::visit_expr_opt(oexpr, cx, v); - if !add_block_exit(cx, func) { leave_fn(cx); } - } - expr_fail(oexpr) { - visit::visit_expr_opt(oexpr, cx, v); - leave_fn(cx); - } - expr_break { add_block_exit(cx, lp); } - expr_while(_, _) | expr_loop(_) { - visit_block(lp, cx) {|| visit::visit_expr(ex, cx, v);} - } - expr_alt(input, arms, _) { - v.visit_expr(input, cx, v); - let before = cx.current; - let mut sets = []; - for arms.each {|arm| - cx.current = before; - v.visit_arm(arm, cx, v); - sets += [cx.current]; - } - cx.current = join_branches(sets); - } - expr_if(cond, then, els) { - v.visit_expr(cond, cx, v); - let mut cur = cx.current; - visit::visit_block(then, cx, v); - cx.current <-> cur; - visit::visit_expr_opt(els, cx, v); - cx.current = join_branches([cur, cx.current]); - } - expr_path(_) { - let my_def = cx.def_map.get(ex.id); - let my_def_id = ast_util::def_id_of_def(my_def).node; - alt cx.ref_map.find(my_def_id) { - option::some(root_id) { - clear_in_current(cx, root_id, false); - } - _ { - option::iter(def_is_owned_local(cx, my_def)) {|nid| - clear_in_current(cx, nid, false); - cx.current += [{def: nid, - uses: @cons(var_use(ex.id), @nil)}]; - } - } - } - } - expr_swap(lhs, rhs) { - clear_if_path(cx, lhs, v, false); - clear_if_path(cx, rhs, v, false); - } - expr_move(dest, src) | expr_assign(dest, src) { - v.visit_expr(src, cx, v); - clear_if_path(cx, dest, v, true); - } - expr_assign_op(_, dest, src) { - v.visit_expr(src, cx, v); - v.visit_expr(dest, cx, v); - clear_if_path(cx, dest, v, true); - } - expr_fn_block(_, _, cap_clause) | - expr_fn(_, _, _, cap_clause) { - // n.b.: safe to ignore copies, as if they are unused - // then they are ignored, otherwise they will show up - // as freevars in the body. - for (*cap_clause).each { |ci| - if ci.is_move { - clear_def_if_local(cx, cx.def_map.get(ci.id), false); - } - } - visit::visit_expr(ex, cx, v); - } - expr_call(f, args, _) { - v.visit_expr(f, cx, v); - let mut fns = []; - let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f)); - vec::iter2(args, arg_ts) {|arg, arg_t| - alt arg.node { - expr_fn(*) | expr_fn_block(*) - if is_blockish(ty::ty_fn_proto(arg_t.ty)) { - fns += [arg]; - } - _ { - alt ty::arg_mode(cx.tcx, arg_t) { - by_mutbl_ref { clear_if_path(cx, arg, v, false); } - _ { v.visit_expr(arg, cx, v); } - } - } - } - } - for fns.each {|f| v.visit_expr(f, cx, v); } - vec::iter2(args, arg_ts) {|arg, arg_t| - alt arg.node { - expr_path(_) { - alt ty::arg_mode(cx.tcx, arg_t) { - by_ref | by_val | by_mutbl_ref { - let def = cx.def_map.get(arg.id); - option::iter(def_is_owned_local(cx, def)) {|id| - clear_in_current(cx, id, false); - cx.spill_map.insert(id, ()); - } - } - _ {} - } - } - _ {} - } - } - } - _ { visit::visit_expr(ex, cx, v); } - } -} - -fn visit_stmt(s: @stmt, cx: ctx, v: visit::vt) { - alt s.node { - stmt_decl(@{node: decl_local(ls), _}, _) { - shadow_in_current(cx, {|id| - let mut rslt = false; - for ls.each {|local| - let mut found = false; - pat_util::pat_bindings(cx.tcx.def_map, local.node.pat, - {|pid, _a, _b| - if pid == id { found = true; } - }); - if found { rslt = true; break; } - } - rslt - }); - } - _ {} - } - visit::visit_stmt(s, cx, v); -} - -fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, - sp: span, id: node_id, - cx: ctx, v: visit::vt) { - let fty = ty::node_id_to_type(cx.tcx, id); - let proto = ty::ty_fn_proto(fty); - alt proto { - proto_any | proto_block { - visit_block(func, cx, {|| - shadow_in_current(cx, {|id| - vec::any(decl.inputs, {|arg| arg.id == id}) - }); - visit::visit_fn(fk, decl, body, sp, id, cx, v); - }); - } - proto_box | proto_uniq | proto_bare { - alt cx.tcx.freevars.find(id) { - some(vars) { - for vec::each(*vars) {|v| - option::iter(def_is_owned_local(cx, v.def)) {|nid| - clear_in_current(cx, nid, false); - cx.current += [{def: nid, - uses: @cons(close_over(id), @nil)}]; - } - } - } - _ {} - } - let mut old_cur = [], old_blocks = @nil; - cx.blocks <-> old_blocks; - cx.current <-> old_cur; - visit::visit_fn(fk, decl, body, sp, id, cx, v); - cx.blocks <-> old_blocks; - leave_fn(cx); - cx.current <-> old_cur; - } - } -} - -fn visit_block(tp: block_type, cx: ctx, visit: fn()) { - let local = @{type: tp, mut second: false, mut exits: []}; - cx.blocks = @cons(local, cx.blocks); - visit(); - local.second = true; - local.exits = []; - visit(); - let cx_blocks = cx.blocks; - cx.blocks = tail(cx_blocks); - local.exits += [cx.current]; - cx.current = join_branches(local.exits); -} - -fn add_block_exit(cx: ctx, tp: block_type) -> bool { - let mut cur = cx.blocks; - loop { - alt *cur { - cons(b, tail) { - if (b.type == tp) { - if !b.second { b.exits += [cx.current]; } - ret true; - } - cur = tail; - } - nil { - ret false; - } - } - } -} - -fn join_branches(branches: [set]) -> set { - let mut found: set = [], i = 0u; - let l = vec::len(branches); - for branches.each {|set| - i += 1u; - for set.each {|elt| - if !vec::any(found, {|v| v.def == elt.def}) { - let mut j = i, nne = elt.uses; - while j < l { - for vec::each(branches[j]) {|elt2| - if elt2.def == elt.def { - list::iter(elt2.uses) {|e| - if !list::has(nne, e) { nne = @cons(e, nne); } - } - } - } - j += 1u; - } - found += [{def: elt.def, uses: nne}]; - } - } - } - ret found; -} - -fn leave_fn(cx: ctx) { - for cx.current.each {|elt| - list::iter(elt.uses) {|use| - let key = alt use { - var_use(pth_id) { path(pth_id) } - close_over(fn_id) { close(fn_id, elt.def) } - }; - if !cx.last_uses.contains_key(key) { - cx.last_uses.insert(key, true); - } - } - } -} - -fn shadow_in_current(cx: ctx, p: fn(node_id) -> bool) { - let mut out = []; - cx.current <-> out; - for out.each {|e| if !p(e.def) { cx.current += [e]; } } -} - -fn clear_in_current(cx: ctx, my_def: node_id, to: bool) { - for cx.current.each {|elt| - if elt.def == my_def { - list::iter(elt.uses) {|use| - let key = alt use { - var_use(pth_id) { path(pth_id) } - close_over(fn_id) { close(fn_id, elt.def) } - }; - if !to || !cx.last_uses.contains_key(key) { - cx.last_uses.insert(key, to); - } - } - cx.current = vec::filter(copy cx.current, {|x| x.def != my_def}); - break; - } - } -} - -fn def_is_owned_local(cx: ctx, d: def) -> option { - alt d { - def_local(id, _) { some(id) } - def_arg(id, m) { - alt ty::resolved_mode(cx.tcx, m) { - by_copy | by_move { some(id) } - by_ref | by_val | by_mutbl_ref { none } - } - } - def_upvar(_, d, fn_id) { - if is_blockish(ty::ty_fn_proto(ty::node_id_to_type(cx.tcx, fn_id))) { - def_is_owned_local(cx, *d) - } else { none } - } - _ { none } - } -} - -fn clear_def_if_local(cx: ctx, d: def, to: bool) { - alt def_is_owned_local(cx, d) { - some(nid) { clear_in_current(cx, nid, to); } - _ {} - } -} - -fn clear_if_path(cx: ctx, ex: @expr, v: visit::vt, to: bool) { - alt ex.node { - expr_path(_) { clear_def_if_local(cx, cx.def_map.get(ex.id), to); } - _ { v.visit_expr(ex, cx, v); } - } -} diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index d7318143adf1..add1484e190f 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -57,6 +57,7 @@ import capture::{cap_move, cap_drop, cap_copy, cap_ref}; export check_crate; export last_use_map; +export spill_map; // Maps from an expr id to a list of variable ids for which this expr // is the last use. Typically, the expr is a path and the node id is @@ -84,7 +85,7 @@ enum live_node_kind { fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - crate: @crate) -> last_use_map { + crate: @crate) -> (last_use_map, spill_map) { let visitor = visit::mk_vt(@{ visit_fn: visit_fn, visit_local: visit_local, @@ -98,7 +99,7 @@ fn check_crate(tcx: ty::ctxt, last_use_map, spill_map); visit::visit_crate(*crate, initial_maps, visitor); tcx.sess.abort_if_errors(); - ret last_use_map; + ret (last_use_map, spill_map); } impl of to_str::to_str for live_node { @@ -141,7 +142,13 @@ enum relevant_def { rdef_var(node_id), rdef_self } type capture_info = {ln: live_node, is_move: bool, rv: relevant_def}; -type var_info = {id: node_id, name: str}; +enum var_kind { + vk_arg(node_id, str, rmode), + vk_local(node_id, str), + vk_field(str), + vk_self, + vk_implicit_ret +} fn relevant_def(def: def) -> option { alt def { @@ -163,7 +170,7 @@ class ir_maps { let variable_map: hashmap; let field_map: hashmap; let capture_map: hashmap; - let mut var_infos: [var_info]; + let mut var_kinds: [var_kind]; let mut lnks: [live_node_kind]; new(tcx: ty::ctxt, method_map: typeck::method_map, @@ -179,7 +186,7 @@ class ir_maps { self.variable_map = int_hash(); self.capture_map = int_hash(); self.field_map = str_hash(); - self.var_infos = []; + self.var_kinds = []; self.lnks = []; } @@ -200,13 +207,23 @@ class ir_maps { #debug["%s is node %d", ln.to_str(), node_id]; } - fn add_variable(node_id: node_id, name: str) -> variable { + fn add_variable(vk: var_kind) -> variable { let v = variable(self.num_vars); - self.variable_map.insert(node_id, v); - self.var_infos += [{id:node_id, name:name}]; + self.var_kinds += [vk]; self.num_vars += 1u; - #debug["%s is node %d", v.to_str(), node_id]; + alt vk { + vk_local(node_id, _) | vk_arg(node_id, _, _) { + self.variable_map.insert(node_id, v); + } + vk_field(name) { + self.field_map.insert(name, v); + } + vk_self | vk_implicit_ret { + } + } + + #debug["%s is %?", v.to_str(), vk]; v } @@ -221,6 +238,15 @@ class ir_maps { } } + fn variable_name(var: variable) -> str { + alt self.var_kinds[*var] { + vk_local(_, name) | vk_arg(_, name, _) {name} + vk_field(name) {"self." + name} + vk_self {"self"} + vk_implicit_ret {""} + } + } + fn set_captures(node_id: node_id, +cs: [capture_info]) { self.capture_map.insert(node_id, @cs); } @@ -238,24 +264,40 @@ class ir_maps { self.lnks[*ln] } - fn add_last_use(expr_id: node_id, var: variable) { - let v = alt self.last_use_map.find(expr_id) { - some(v) { v } - none { - let v = @dvec(); - self.last_use_map.insert(expr_id, v); - v + fn add_spill(var: variable) { + let vk = self.var_kinds[*var]; + alt vk { + vk_local(id, _) | vk_arg(id, _, by_val) { + #debug["adding spill for %?", vk]; + self.spill_map.insert(id, ()); } - }; - let {id, name} = self.var_infos[*var]; - #debug["Node %d is a last use of variable %d / %s", - expr_id, id, name]; - (*v).push(id); + vk_arg(*) | vk_field(_) | vk_self | vk_implicit_ret {} + } } - fn add_spill(var: variable) { - let id = self.var_infos[*var].id; - if id != 0 { self.spill_map.insert(id, ()); } + fn add_last_use(expr_id: node_id, var: variable) { + let vk = self.var_kinds[*var]; + #debug["Node %d is a last use of variable %?", expr_id, vk]; + alt vk { + vk_arg(id, name, by_move) | + vk_arg(id, name, by_copy) | + vk_local(id, name) { + let v = alt self.last_use_map.find(expr_id) { + some(v) { v } + none { + let v = @dvec(); + self.last_use_map.insert(expr_id, v); + v + } + }; + + (*v).push(id); + } + vk_arg(_, _, by_ref) | vk_arg(_, _, by_mutbl_ref) | + vk_arg(_, _, by_val) | vk_self | vk_field(_) | vk_implicit_ret { + #debug["--but it is not owned"]; + } + } } } @@ -272,7 +314,8 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, for decl.inputs.each { |arg| #debug["adding argument %d", arg.id]; - (*fn_maps).add_variable(arg.id, arg.ident); + let mode = ty::resolved_mode(self.tcx, arg.mode); + (*fn_maps).add_variable(vk_arg(arg.id, arg.ident, mode)); }; // gather up the various local variables, significant expressions, @@ -293,8 +336,8 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, let specials = { exit_ln: (*fn_maps).add_live_node(lnk_exit), fallthrough_ln: (*fn_maps).add_live_node(lnk_exit), - no_ret_var: (*fn_maps).add_variable(0, ""), - self_var: (*fn_maps).add_variable(0, "self") + no_ret_var: (*fn_maps).add_variable(vk_implicit_ret), + self_var: (*fn_maps).add_variable(vk_self) }; // compute liveness @@ -317,8 +360,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, fn add_class_fields(self: @ir_maps, did: def_id) { for ty::lookup_class_fields(self.tcx, did).each { |field_ty| assert field_ty.id.crate == local_crate; - let var = (*self).add_variable( - field_ty.id.node, #fmt["self.%s", field_ty.ident]); + let var = (*self).add_variable(vk_field(field_ty.ident)); self.field_map.insert(field_ty.ident, var); } } @@ -329,7 +371,7 @@ fn visit_local(local: @local, &&self: @ir_maps, vt: vt<@ir_maps>) { #debug["adding local variable %d", p_id]; let name = ast_util::path_to_ident(path); (*self).add_live_node_for_node(p_id, lnk_vdef(sp)); - (*self).add_variable(p_id, name); + (*self).add_variable(vk_local(p_id, name)); } visit::visit_local(local, self, vt); } @@ -730,6 +772,9 @@ class liveness { } } + // as above, the "self" variable is a non-owned variable + self.acc(self.s.exit_ln, self.s.self_var, ACC_READ); + // in a ctor, there is an implicit use of self.f for all fields f: for self.ir.field_map.each_value { |var| self.acc(self.s.exit_ln, var, ACC_READ|ACC_USE); @@ -938,8 +983,8 @@ class liveness { // see comment on lvalues in // propagate_through_lvalue_components() let succ = self.write_lvalue(l, succ, ACC_WRITE); - let succ = self.propagate_through_expr(r, succ); - self.propagate_through_lvalue_components(l, succ) + let succ = self.propagate_through_lvalue_components(l, succ); + self.propagate_through_expr(r, succ) } expr_swap(l, r) { @@ -1063,14 +1108,11 @@ class liveness { // ----------------------++----------------------- // || // | || | - // | || v - // | || (lvalue components) - // | || | // v || v // (rvalue) || (rvalue) // | || | - // v || | - // (write of lvalue) || | + // v || v + // (write of lvalue) || (lvalue components) // | || | // v || v // (succ) || (succ) @@ -1604,7 +1646,7 @@ impl check_methods for @liveness { possibly_uninitialized_field {"possibly uninitialized field"} moved_variable {"moved variable"} }; - let name = self.ir.var_infos[*var].name; + let name = (*self.ir).variable_name(var); alt lnk { lnk_freevar(span) { self.tcx.sess.span_err( @@ -1625,7 +1667,7 @@ impl check_methods for @liveness { } fn should_warn(var: variable) -> option { - let name = self.ir.var_infos[*var].name; + let name = (*self.ir).variable_name(var); if name[0] == ('_' as u8) {none} else {some(name)} } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index aece631bf5d3..e2feeed49df1 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2832,7 +2832,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr, } else if arg_mode == ast::by_copy || arg_mode == ast::by_move { let alloc = alloc_ty(bcx, arg.ty); let move_out = arg_mode == ast::by_move || - ccx.maps.last_uses.contains_key(e.id); + ccx.maps.last_use_map.contains_key(e.id); if lv.kind == temporary { revoke_clean(bcx, val); } if lv.kind == owned || !ty::type_is_immediate(arg.ty) { memmove_ty(bcx, alloc, val, arg.ty); @@ -3561,7 +3561,8 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { let src_r = trans_temp_lval(bcx, src); let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst); assert kind == owned; - let is_last_use = bcx.ccx().maps.last_uses.contains_key(src.id); + let is_last_use = + bcx.ccx().maps.last_use_map.contains_key(src.id); ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r, expr_ty(bcx, src), is_last_use); } @@ -3639,10 +3640,10 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { } fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block { - let last_uses = bcx.ccx().maps.last_uses; + let last_use_map = bcx.ccx().maps.last_use_map; let ty = expr_ty(bcx, e); let lv = trans_lval(bcx, e); - let last_use = (lv.kind == owned && last_uses.contains_key(e.id)); + let last_use = (lv.kind == owned && last_use_map.contains_key(e.id)); lval_result_to_dps(lv, ty, last_use, dest) } diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs index bfc93ddf93d6..348f90ae6ace 100644 --- a/src/rustc/middle/trans/closure.rs +++ b/src/rustc/middle/trans/closure.rs @@ -18,6 +18,7 @@ import util::ppaux::ty_to_str; import syntax::ast_map::{path, path_mod, path_name}; import driver::session::session; import std::map::hashmap; +import dvec::extensions; // ___Good to know (tm)__________________________________________________ // @@ -307,9 +308,9 @@ fn build_closure(bcx0: block, env_vals += [env_ref(lv.val, ty, lv.kind)]; } capture::cap_copy { - let mv = alt check ccx.maps.last_uses.find(id) { + let mv = alt check ccx.maps.last_use_map.find(id) { none { false } - some(last_use::closes_over(vars)) { vec::contains(vars, nid) } + some(vars) { (*vars).contains(nid) } }; if mv { env_vals += [env_move(lv.val, ty, lv.kind)]; } else { env_vals += [env_copy(lv.val, ty, lv.kind)]; } diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 4ba01859cdd5..81f5f467847a 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -71,7 +71,6 @@ mod middle { mod lint; mod borrowck; mod alias; - mod last_use; mod liveness; mod block_use; mod kind; diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index 9d10aa407348..d2bd85afc2a5 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -10,7 +10,7 @@ fn start(+token: int) { let mut ch = comm::chan(p); int::range(2, n_threads + 1) { |i| let id = n_threads + 2 - i; - let to_child = task::spawn_listener:: {|p| + let to_child = task::spawn_listener:: {|p, copy ch| roundtrip(id, p, ch) }; ch = to_child;