diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-06-07 19:42:22 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-06-07 19:42:27 -0700 |
| commit | 7ef825bb607c4e934c92bd0b73ecbc4c24f3286b (patch) | |
| tree | c5800f031f1959f2d91c61b890547a3b37f3a0af /src | |
| parent | c058f1d9927874fd5bfe40d5e6698880a07c36bb (diff) | |
| download | rust-7ef825bb607c4e934c92bd0b73ecbc4c24f3286b.tar.gz rust-7ef825bb607c4e934c92bd0b73ecbc4c24f3286b.zip | |
Revert "remove alias analysis and replace with borrowck"
18s perf regression compiling rustc with opts This reverts commit 7f6ee0ce0df8af4c21b065cb49b95079ae643f77.
Diffstat (limited to 'src')
50 files changed, 1057 insertions, 30 deletions
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 769f3c40e25..672a950f42b 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -204,6 +204,9 @@ 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) = + time(time_passes, "alias checking", + bind middle::alias::check_crate(ty_cx, crate)); time(time_passes, "kind checking", bind kind::check_crate(ty_cx, method_map, last_use_map, crate)); time(time_passes, "lint checking", @@ -213,7 +216,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, - last_use_map: last_use_map, + copy_map: copy_map, last_use_map: last_use_map, impl_map: impl_map, method_map: method_map, vtable_map: vtable_map}; @@ -445,6 +448,14 @@ fn build_session_options(match: getopts::match, let sysroot_opt = getopts::opt_maybe_str(match, "sysroot"); let target_opt = getopts::opt_maybe_str(match, "target"); let save_temps = getopts::opt_present(match, "save-temps"); + let borrowck = alt getopts::opt_maybe_str(match, "borrowck") { + none { 0u } + some("warn") { 1u } + some("err") { 2u } + some(_) { + early_error(demitter, "borrowck may be warn or err") + } + }; alt output_type { // unless we're emitting huamn-readable assembly, omit comments. link::output_type_llvm_assembly | link::output_type_assembly {} @@ -493,7 +504,8 @@ fn build_session_options(match: getopts::match, test: test, parse_only: parse_only, no_trans: no_trans, - debugging_opts: debugging_opts}; + debugging_opts: debugging_opts, + borrowck: borrowck}; ret sopts; } @@ -570,7 +582,8 @@ fn opts() -> [getopts::opt] { optmulti("Z"), optmulti("cfg"), optflag("test"), - optflag("lib"), optflag("bin"), optflag("static"), optflag("gc")]; + optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"), + optopt("borrowck")]; } type output_filenames = @{out_filename: str, obj_filename:str}; diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index 07f42a0d269..97e2d0ec4db 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -66,6 +66,9 @@ type options = no_trans: bool, debugging_opts: uint, + + // temporary hack: 0=off,1=warn,2=err --> if 2, alias is disabled + borrowck: uint, }; type crate_metadata = {name: str, data: [u8]}; @@ -178,7 +181,8 @@ fn basic_options() -> @options { test: false, parse_only: false, no_trans: false, - debugging_opts: 0u + debugging_opts: 0u, + borrowck: 0u, } } diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs index ba23dd24baa..a754d4c11a2 100644 --- a/src/rustc/metadata/common.rs +++ b/src/rustc/metadata/common.rs @@ -116,6 +116,7 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f tag_table_param_bounds, tag_table_inferred_modes, tag_table_mutbl, + tag_table_copy, tag_table_last_use, tag_table_spill, tag_table_method_map, diff --git a/src/rustc/middle/alias.rs b/src/rustc/middle/alias.rs new file mode 100644 index 00000000000..1fb17d4f385 --- /dev/null +++ b/src/rustc/middle/alias.rs @@ -0,0 +1,847 @@ +import syntax::{ast, ast_util, ast_map}; +import ast_util::path_to_ident; +import ast::{ident, fn_ident, node_id}; +import syntax::codemap::span; +import syntax::visit; +import visit::vt; +import std::list; +import std::map::hashmap; +import core::unreachable; +import option::is_none; +import list::list; +import driver::session::session; +import pat_util::*; +import util::ppaux::ty_to_str; + +// This is not an alias-analyser (though it would merit from becoming one, or +// getting input from one, to be more precise). It is a pass that checks +// whether aliases are used in a safe way. + +enum copied { not_allowed, copied, not_copied, } +enum invalid_reason { overwritten, val_taken, } +type invalid = {reason: invalid_reason, + node_id: node_id, + sp: span, path: @ast::path}; + +enum unsafe_ty { contains(ty::t), mutbl_contains(ty::t), } + +type binding = @{node_id: node_id, + span: span, + root_var: option<node_id>, + local_id: uint, + unsafe_tys: [unsafe_ty], + mut copied: copied}; + +// FIXME it may be worthwhile to use a linked list of bindings instead +type scope = {bs: [binding], + invalid: @mut @list<@invalid>}; + +fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option<node_id>, + unsafe_tys: [unsafe_ty]) -> binding { + alt root_var { + some(r_id) { cx.ref_map.insert(id, r_id); } + _ {} + } + ret @{node_id: id, span: span, root_var: root_var, + local_id: local_id_of_node(cx, id), + unsafe_tys: unsafe_tys, + mut copied: not_copied}; +} + +enum local_info { local(uint), } + +type copy_map = std::map::hashmap<node_id, ()>; +type ref_map = std::map::hashmap<node_id, node_id>; + +type ctx = {tcx: ty::ctxt, + copy_map: copy_map, + ref_map: ref_map, + mut silent: bool}; + +fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) { + // Stores information about function arguments that's otherwise not easily + // available. + let cx = @{tcx: tcx, + copy_map: std::map::int_hash(), + ref_map: std::map::int_hash(), + mut silent: false}; + let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _), + visit_expr: bind visit_expr(cx, _, _, _), + visit_block: bind visit_block(cx, _, _, _) + with *visit::default_visitor::<scope>()}; + let sc = {bs: [], invalid: @mut @list::nil}; + visit::visit_crate(*crate, sc, visit::mk_vt(v)); + tcx.sess.abort_if_errors(); + ret (cx.copy_map, cx.ref_map); +} + +fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl, + body: ast::blk, _sp: span, + id: ast::node_id, sc: scope, v: vt<scope>) { + visit::visit_fn_decl(decl, sc, v); + let fty = ty::node_id_to_type(cx.tcx, id); + + // Blocks need to obey any restrictions from the enclosing scope, and may + // be called multiple times. + let proto = ty::ty_fn_proto(fty); + alt proto { + ast::proto_block | ast::proto_any { + check_loop(*cx, sc) {|| v.visit_block(body, sc, v);} + } + ast::proto_box | ast::proto_uniq | ast::proto_bare { + let sc = {bs: [], invalid: @mut @list::nil}; + v.visit_block(body, sc, v); + } + } +} + +fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) { + let mut handled = true; + alt ex.node { + ast::expr_call(f, args, _) { + check_call(cx, sc, f, args, v); + visit_expr(cx, f, sc, v); + } + ast::expr_alt(input, arms, _) { check_alt(*cx, input, arms, sc, v); } + ast::expr_path(pt) { + check_var(*cx, ex, pt, ex.id, false, sc); + handled = false; + } + ast::expr_swap(lhs, rhs) { + check_lval(cx, lhs, sc, v); + check_lval(cx, rhs, sc, v); + handled = false; + } + ast::expr_move(dest, src) { + visit_expr(cx, src, sc, v); + check_lval(cx, dest, sc, v); + check_lval(cx, src, sc, v); + } + ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) { + visit_expr(cx, src, sc, v); + check_lval(cx, dest, sc, v); + } + ast::expr_if(c, then, els) { check_if(c, then, els, sc, v); } + ast::expr_while(_, _) { + check_loop(*cx, sc) {|| visit::visit_expr(ex, sc, v); } + } + _ { handled = false; } + } + if !handled { visit::visit_expr(ex, sc, v); } +} + +fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) { + let sc = sc; + for b.node.stmts.each {|stmt| + alt stmt.node { + ast::stmt_decl(@{node: ast::decl_item(it), _}, _) { + v.visit_item(it, sc, v); + } + ast::stmt_decl(@{node: ast::decl_local(locs), _}, _) { + for locs.each {|loc| + alt loc.node.init { + some(init) { + if init.op == ast::init_move { + check_lval(cx, init.expr, sc, v); + } else { + visit_expr(cx, init.expr, sc, v); + } + } + none { } + } + } + } + ast::stmt_expr(ex, _) | ast::stmt_semi(ex, _) { + v.visit_expr(ex, sc, v); + } + } + } + visit::visit_expr_opt(b.node.expr, sc, v); +} + +fn cant_copy(cx: ctx, b: binding) -> bool { + + if cx.tcx.sess.opts.borrowck == 2u { + // borrowck is enabled. disable alias analysis. + ret false; + } + + alt b.copied { + not_allowed { ret true; } + copied { ret false; } + not_copied {} + } + let ty = ty::node_id_to_type(cx.tcx, b.node_id); + if ty::type_allows_implicit_copy(cx.tcx, ty) { + b.copied = copied; + cx.copy_map.insert(b.node_id, ()); + if copy_is_expensive(cx.tcx, ty) { + cx.tcx.sess.span_warn(b.span, + "inserting an implicit copy for type " + + util::ppaux::ty_to_str(cx.tcx, ty)); + } + ret false; + } else { ret true; } +} + +// FIXME this is a really awful hack +fn local_id_for_args(cx: ctx, args: [@ast::expr]) -> uint { + for vec::each(args) {|arg| + alt arg.node { + ast::expr_fn_block(decl, _, _) | ast::expr_fn(_, decl, _, _) | + ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _, _), _}) { + if decl.inputs.len() > 0u { + ret local_id_of_node(cx, decl.inputs[0].id); + } + } + _ {} + } + } + 0xFFFFFFFFu +} + +fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr], + v: vt<scope>) { + let fty = ty::expr_ty(cx.tcx, f); + let arg_ts = ty::ty_fn_args(fty); + let mut mut_roots: [{arg: @ast::expr, node: node_id}] = []; + let mut bindings = []; + let mut blocks = [], loc_id = local_id_for_args(*cx, args); + vec::iter2(args, arg_ts) {|arg, arg_t| + let root = expr_root(*cx, arg, false); + alt ty::resolved_mode(cx.tcx, arg_t.mode) { + ast::by_mutbl_ref { + alt path_def(*cx, arg) { + some(def) { + let dnum = ast_util::def_id_of_def(def).node; + mut_roots += [{arg: arg, node: dnum}]; + } + _ { } + } + } + ast::by_ref | ast::by_val | ast::by_move | ast::by_copy {} + } + alt arg.node { + ast::expr_fn_block(*) { blocks += [arg]; } + ast::expr_loop_body(b) { blocks += [b]; } + _ { + let root_var = path_def_id(*cx, root.ex); + let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) { + ast::by_move | ast::by_copy { copied } + ast::by_mutbl_ref { not_allowed } + ast::by_ref | ast::by_val { not_copied } + }; + visit_expr(cx, arg, sc, v); + bindings += [@{node_id: arg.id, + span: arg.span, + root_var: root_var, + local_id: loc_id, + unsafe_tys: unsafe_set(root.mutbl), + mut copied: arg_copied}]; + } + } + } + let f_may_close = alt f.node { + ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) } + _ { true } + }; + if f_may_close { + let mut i = 0u; + for bindings.each {|b| + let mut unsfe = vec::len(b.unsafe_tys) > 0u; + alt b.root_var { + some(rid) { + for sc.bs.each {|o| + if o.node_id == rid && vec::len(o.unsafe_tys) > 0u { + unsfe = true; break; + } + } + } + _ {} + } + if unsfe && cant_copy(*cx, b) { + err(*cx, f.span, #fmt["function may alias with argument \ + %u, which is not immutably rooted", i]); + } + i += 1u; + } + } + let mut j = 0u; + for bindings.each {|b| + for b.unsafe_tys.each {|unsafe_ty| + vec::iteri(arg_ts) {|i, arg_t| + let mut_alias = + (ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t)); + alt args[i].node { + ast::expr_fn_block(*) | ast::expr_loop_body(_) {} + _ { + if i != j && ty_can_unsafely_include( + *cx, unsafe_ty, arg_t.ty, mut_alias) && + cant_copy(*cx, b) { + err(*cx, args[i].span, + #fmt["argument %u may alias with argument %u, \ + which is not immutably rooted", i, j]); + } + } + } + } + } + j += 1u; + } + + // Ensure we're not passing a root by mut alias. + for mut_roots.each {|mroot| + for bindings.each {|b| + if b.node_id != mroot.arg.id { + alt b.root_var { + some(root) { + if mroot.node == root && cant_copy(*cx, b) { + err(*cx, mroot.arg.span, + "passing a mut reference to a \ + variable that roots another reference"); + break; + } + } + none { } + } + } + } + } + // Check the bodies of block arguments against the current scope + if blocks.len() > 0u { + let inner_sc = {bs: bindings + sc.bs, invalid: sc.invalid}; + for blocks.each {|blk| + alt check blk.node { + ast::expr_fn_block(_, body, _) { + v.visit_block(body, inner_sc, v); + } + } + } + for bindings.each {|binding| + test_scope(*cx, sc, binding, none); + } + } +} + +#[warn(no_non_implicitly_copyable_typarams)] +fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope, + v: vt<scope>) { + v.visit_expr(input, sc, v); + let orig_invalid = *sc.invalid; + let mut all_invalid = orig_invalid; + let root = expr_root(cx, input, true); + for arms.each {|a| + let mut new_bs = sc.bs; + let root_var = path_def_id(cx, root.ex); + let pat_id_map = pat_util::pat_id_map(cx.tcx.def_map, a.pats[0]); + type info = { + id: node_id, + mut unsafe_tys: [unsafe_ty], + span: span}; + let mut binding_info: [info] = []; + for a.pats.each {|pat| + for pattern_roots(cx.tcx, root.mutbl, pat).each {|proot| + let canon_id = pat_id_map.get(proot.name); + alt vec::find(binding_info, {|x| x.id == canon_id}) { + some(s) { s.unsafe_tys += unsafe_set(proot.mutbl); } + none { + binding_info += [ + {id: canon_id, + mut unsafe_tys: unsafe_set(proot.mutbl), + span: proot.span}]; + } + } + } + } + for binding_info.each {|info| + new_bs += [mk_binding(cx, info.id, info.span, root_var, + copy info.unsafe_tys)]; + }; + *sc.invalid = orig_invalid; + visit::visit_arm(a, {bs: new_bs with sc}, v); + all_invalid = join_invalid(all_invalid, *sc.invalid); + }; + *sc.invalid = all_invalid; +} + +fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk, + sc: scope, v: vt<scope>) { + let root = expr_root(cx, seq, false); + + // If this is a mut vector, don't allow it to be touched. + let seq_t = ty::expr_ty(cx.tcx, seq); + let mut cur_mutbl = root.mutbl; + alt ty::get(seq_t).struct { + ty::ty_vec(mt) { + if mt.mutbl != ast::m_imm { + cur_mutbl = some(contains(seq_t)); + } + } + _ {} + } + let root_var = path_def_id(cx, root.ex); + let mut new_bs = sc.bs; + for pattern_roots(cx.tcx, cur_mutbl, local.node.pat).each {|proot| + new_bs += [mk_binding(cx, proot.id, proot.span, root_var, + unsafe_set(proot.mutbl))]; + } + visit::visit_block(blk, {bs: new_bs with sc}, v); +} + +fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id, + assign: bool, sc: scope) { + let def = cx.tcx.def_map.get(id); + if !def_is_local_or_self(def) { ret; } + let my_defnum = ast_util::def_id_of_def(def).node; + let my_local_id = local_id_of_node(cx, my_defnum); + let var_t = ty::expr_ty(cx.tcx, ex); + for sc.bs.each {|b| + // excludes variables introduced since the alias was made + if my_local_id < b.local_id { + for b.unsafe_tys.each {|unsafe_ty| + if ty_can_unsafely_include(cx, unsafe_ty, var_t, assign) { + let inv = @{reason: val_taken, node_id: b.node_id, + sp: ex.span, path: p}; + *sc.invalid = @list::cons(inv, *sc.invalid); + } + } + } else if b.node_id == my_defnum { + test_scope(cx, sc, b, some(p)); + } + } +} + +fn check_lval(cx: @ctx, dest: @ast::expr, sc: scope, v: vt<scope>) { + alt dest.node { + ast::expr_path(p) { + let def = cx.tcx.def_map.get(dest.id); + let dnum = ast_util::def_id_of_def(def).node; + for sc.bs.each {|b| + if b.root_var == some(dnum) { + let inv = @{reason: overwritten, node_id: b.node_id, + sp: dest.span, path: p}; + *sc.invalid = @list::cons(inv, *sc.invalid); + } + } + } + _ { visit_expr(cx, dest, sc, v); } + } +} + +fn check_if(c: @ast::expr, then: ast::blk, els: option<@ast::expr>, + sc: scope, v: vt<scope>) { + v.visit_expr(c, sc, v); + let orig_invalid = *sc.invalid; + v.visit_block(then, sc, v); + let then_invalid = *sc.invalid; + *sc.invalid = orig_invalid; + visit::visit_expr_opt(els, sc, v); + *sc.invalid = join_invalid(*sc.invalid, then_invalid); +} + +fn check_loop(cx: ctx, sc: scope, checker: fn()) { + let orig_invalid = filter_invalid(*sc.invalid, sc.bs); + checker(); + let new_invalid = filter_invalid(*sc.invalid, sc.bs); + // Have to check contents of loop again if it invalidated an alias + if list::len(orig_invalid) < list::len(new_invalid) { + let old_silent = cx.silent; + cx.silent = true; + checker(); + cx.silent = old_silent; + } + *sc.invalid = new_invalid; +} + +fn test_scope(cx: ctx, sc: scope, b: binding, p: option<@ast::path>) { + let mut prob = find_invalid(b.node_id, *sc.invalid); + alt b.root_var { + some(dn) { + for sc.bs.each {|other| + if !is_none(prob) { break; } + if other.node_id == dn { + prob = find_invalid(other.node_id, *sc.invalid); + } + } + } + _ {} + } + if !is_none(prob) && cant_copy(cx, b) { + let i = option::get(prob); + let msg = alt i.reason { + overwritten { "overwriting " + ast_util::path_name(i.path) } + val_taken { "taking the value of " + ast_util::path_name(i.path) } + }; + let refname = alt p { + some(pt) { "reference " + ast_util::path_name(pt) + + ", which is still used" } + none { "an argument" } + }; + err(cx, i.sp, msg + " will invalidate " + refname); + } +} + +fn path_def(cx: ctx, ex: @ast::expr) -> option<ast::def> { + ret alt ex.node { + ast::expr_path(_) { some(cx.tcx.def_map.get(ex.id)) } + _ { none } + } +} + +fn path_def_id(cx: ctx, ex: @ast::expr) -> option<ast::node_id> { + alt ex.node { + ast::expr_path(_) { + ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)).node); + } + _ { ret none; } + } +} + +fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t, + mutbl: bool) -> bool { + fn get_mutbl(cur: bool, mt: ty::mt) -> bool { + ret cur || mt.mutbl != ast::m_imm; + } + fn helper(tcx: ty::ctxt, needle: unsafe_ty, haystack: ty::t, mutbl: bool) + -> bool { + if alt needle { + contains(ty) { ty == haystack } + mutbl_contains(ty) { mutbl && ty == haystack } + } { ret true; } + alt ty::get(haystack).struct { + ty::ty_enum(_, ts) { + for ts.tps.each {|t| + if helper(tcx, needle, t, mutbl) { ret true; } + } + ret false; + } + ty::ty_box(mt) | ty::ty_ptr(mt) | ty::ty_uniq(mt) { + ret helper(tcx, needle, mt.ty, get_mutbl(mutbl, mt)); + } + ty::ty_rec(fields) { + for fields.each {|f| + if helper(tcx, needle, f.mt.ty, get_mutbl(mutbl, f.mt)) { + ret true; + } + } + ret false; + } + ty::ty_tup(ts) { + for ts.each {|t| if helper(tcx, needle, t, mutbl) { ret true; } } + ret false; + } + ty::ty_fn({proto: ast::proto_bare, _}) { ret false; } + // These may contain anything. + ty::ty_fn(_) | ty::ty_iface(_, _) { ret true; } + // A type param may include everything, but can only be + // treated as opaque downstream, and is thus safe unless we + // saw mut fields, in which case the whole thing can be + // overwritten. + ty::ty_param(_, _) { ret mutbl; } + _ { ret false; } + } + } + ret helper(cx.tcx, needle, haystack, mutbl); +} + +fn def_is_local_or_self(d: ast::def) -> bool { + alt d { + ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) | + ast::def_upvar(_, _, _) | ast::def_self(_) { true } + _ { false } + } +} + +fn local_id_of_node(cx: ctx, id: node_id) -> uint { + alt cx.tcx.items.find(id) { + some(ast_map::node_arg(_, id)) | some(ast_map::node_local(id)) { id } + _ { 0u } + } +} + +// Heuristic, somewhat random way to decide whether to warn when inserting an +// implicit copy. +fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool { + fn score_ty(tcx: ty::ctxt, ty: ty::t) -> uint { + ret alt ty::get(ty).struct { + ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | + ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type | + ty::ty_ptr(_) { 1u } + ty::ty_box(_) | ty::ty_iface(_, _) { 3u } + ty::ty_constr(t, _) | ty::ty_res(_, t, _) { score_ty(tcx, t) } + ty::ty_fn(_) { 4u } + ty::ty_str | ty::ty_vec(_) | ty::ty_param(_, _) { 50u } + ty::ty_uniq(mt) { 1u + score_ty(tcx, mt.ty) } + ty::ty_enum(_, substs) { + substs.tps.foldl(0u) { |sum, t| sum + score_ty(tcx, t) } + } + ty::ty_tup(ts) { + ts.foldl(0u) { |sum, t| sum + score_ty(tcx, t) } + } + ty::ty_rec(fs) { + let mut sum = 0u; + for fs.each {|f| sum += score_ty(tcx, f.mt.ty); } + sum + } + _ { + tcx.sess.warn(#fmt("score_ty: unexpected type %s", + ty_to_str(tcx, ty))); + 1u // ??? + } + }; + } + ret score_ty(tcx, ty) > 8u; +} + +type pattern_root = {id: node_id, + name: ident, + mutbl: option<unsafe_ty>, + span: span}; + +fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat) + -> [pattern_root] { + fn walk(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat, + &set: [pattern_root]) { + alt pat.node { + ast::pat_ident(nm, sub) + if !pat_util::pat_is_variant(tcx.def_map, pat) { + set += [{id: pat.id, name: path_to_ident(nm), mutbl: mutbl, + span: pat.span}]; + option::iter(sub) {|p| walk(tcx, mutbl, p, set); }; + } + ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) | + ast::pat_ident(_, _) | ast::pat_enum(_, none) {} + ast::pat_enum(_, some(ps)) | ast::pat_tup(ps) { + for ps.each {|p| walk(tcx, mutbl, p, set); } + } + ast::pat_rec(fs, _) { + let ty = ty::node_id_to_type(tcx, pat.id); + for fs.each {|f| + let m = ty::get_field(ty, f.ident).mt.mutbl != ast::m_imm, + c = if m { some(contains(ty)) } else { mutbl }; + walk(tcx, c, f.pat, set); + } + } + ast::pat_box(p) { + let ty = ty::node_id_to_type(tcx, pat.id); + let m = alt ty::get(ty).struct { + ty::ty_box(mt) { mt.mutbl != ast::m_imm } + _ { tcx.sess.span_bug(pat.span, "box pat has non-box type"); } + }, + c = if m {some(contains(ty)) } else { mutbl }; + walk(tcx, c, p, set); + } + ast::pat_uniq(p) { + let ty = ty::node_id_to_type(tcx, pat.id); + let m = alt ty::get(ty).struct { + ty::ty_uniq(mt) { mt.mutbl != ast::m_imm } + _ { tcx.sess.span_bug(pat.span, "uniq pat has non-uniq type"); } + }, + c = if m { some(contains(ty)) } else { mutbl }; + walk(tcx, c, p, set); + } + } + } + let mut set = []; + walk(tcx, mutbl, pat, set); + ret set; +} + +enum deref_t { unbox(bool), field, index, } + +type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t}; + +fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) + -> {ex: @ast::expr, mutbl: option<unsafe_ty>} { + + fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} { + let mut ds = [], t = t; + loop { + alt ty::get(t).struct { + ty::ty_box(mt) | ty::ty_uniq(mt) | ty::ty_rptr(_, mt) { + ds += [@{mutbl: mt.mutbl == ast::m_mutbl, + kind: unbox(false), + outer_t: t}]; + t = mt.ty; + } + ty::ty_res(_, inner, substs) { + ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; + t = ty::subst(tcx, substs, inner); + } + ty::ty_enum(did, substs) { + let variants = ty::enum_variants(tcx, did); + if vec::len(*variants) != 1u || + vec::len(variants[0].args) != 1u { + break; + } + ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; + t = ty::subst(tcx, substs, variants[0].args[0]); + } + _ { break; } + } + } + ret {t: t, ds: ds}; + } + + fn expr_root_(tcx: ty::ctxt, ctor_self: option<node_id>, + ex: @ast::expr, autoderef: bool) -> {ex: @ast::expr, + ds: @[deref]} { + let mut ds: [deref] = [], ex = ex; + loop { + alt copy ex.node { + ast::expr_field(base, ident, _) { + let auto_unbox = + maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); + let mut is_mutbl = false; + alt ty::get(auto_unbox.t).struct { + ty::ty_rec(fields) { + for fields.each {|fld| + if str::eq(ident, fld.ident) { + is_mutbl = fld.mt.mutbl == ast::m_mutbl; + break; + } + } + } + ty::ty_class(did, _) { + util::common::log_expr(*base); + let in_self = alt ctor_self { + some(selfid) { + alt tcx.def_map.find(base.id) { + some(ast::def_self(slfid)) { slfid == selfid } + _ { false } + } + } + none { false } + }; + for ty::lookup_class_fields(tcx, did).each {|fld| + if str::eq(ident, fld.ident) { + is_mutbl = fld.mutability == ast::class_mutable + || in_self; // all fields can be mutated + // in the ctor + break; + } + } + } + _ {} + } + ds += [@{mutbl:is_mutbl, kind:field, outer_t:auto_unbox.t}]; + ds += auto_unbox.ds; + ex = base; + } + ast::expr_index(base, _) { + let auto_unbox = + maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); + alt ty::get(auto_unbox.t).struct { + ty::ty_evec(mt, _) | + ty::ty_vec(mt) { + ds += + [@{mutbl: mt.mutbl == ast::m_mutbl, + kind: index, + outer_t: auto_unbox.t}]; + } + ty::ty_estr(_) | + ty::ty_str { + ds += [@{mutbl:false, kind:index, outer_t:auto_unbox.t}]; + } + _ { break; } + } + ds += auto_unbox.ds; + ex = base; + } + ast::expr_unary(op, base) { + if op == ast::deref { + let base_t = ty::expr_ty(tcx, base); + let mut is_mutbl = false, ptr = false; + alt ty::get(base_t).struct { + ty::ty_box(mt) { is_mutbl = mt.mutbl==ast::m_mutbl; } + ty::ty_uniq(mt) { is_mutbl = mt.mutbl==ast::m_mutbl; } + ty::ty_res(_, _, _) { } + ty::ty_enum(_, _) { } + ty::ty_ptr(mt) | ty::ty_rptr(_, mt) { + is_mutbl = mt.mutbl==ast::m_mutbl; + ptr = true; + } + _ { + tcx.sess.span_bug( + base.span, + "ill-typed base expression in deref"); } + } + ds += [@{mutbl: is_mutbl, kind: unbox(ptr && is_mutbl), + outer_t: base_t}]; + ex = base; + } else { break; } + } + _ { break; } + } + } + if autoderef { + let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, ex)); + ds += auto_unbox.ds; + } + ret {ex: ex, ds: @ds}; + } + + let base_root = expr_root_(cx.tcx, none, ex, autoderef); + let mut unsafe_ty = none; + for vec::each(*base_root.ds) {|d| + if d.mutbl { unsafe_ty = some(contains(d.outer_t)); break; } + } + ret {ex: base_root.ex, mutbl: unsafe_ty}; +} + +fn unsafe_set(from: option<unsafe_ty>) -> [unsafe_ty] { + alt from { some(t) { [t] } _ { [] } } +} + +fn find_invalid(id: node_id, lst: @list<@invalid>) -> option<@invalid> { + let mut cur = lst; + loop { + alt *cur { + list::nil { ret none; } + list::cons(head, tail) { + if head.node_id == id { ret some(head); } + cur = tail; + } + } + }; +} + +fn join_invalid(a: @list<@invalid>, b: @list<@invalid>) -> @list<@invalid> { + let mut result = a; + list::iter(b) {|elt| + let mut found = false; + list::iter(a) {|e| if e == elt { found = true; } } + if !found { result = @list::cons(elt, result); } + } + result +} + +fn filter_invalid(src: @list<@invalid>, bs: [binding]) -> @list<@invalid> { + let mut out = @list::nil, cur = src; + loop { + alt *cur { + list::cons(head, tail) { + let p = vec::position(bs, {|b| b.node_id == head.node_id}); + if !is_none(p) { out = @list::cons(head, out); } + cur = tail; + } + list::nil { + ret out; + } + } + } +} + +fn err(cx: ctx, sp: span, err: str) { + if !cx.silent || !cx.tcx.sess.has_errors() { + cx.tcx.sess.span_err(sp, err); + } +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index d604505455c..bcf6c799739 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -52,6 +52,7 @@ export decode_inlined_item; type maps = { mutbl_map: middle::borrowck::mutbl_map, root_map: middle::borrowck::root_map, + copy_map: middle::alias::copy_map, last_use_map: middle::liveness::last_use_map, impl_map: middle::resolve::impl_map, method_map: middle::typeck::method_map, @@ -830,6 +831,12 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, } } + option::iter(maps.copy_map.find(id)) {|_m| + ebml_w.tag(c::tag_table_copy) {|| + ebml_w.id(id); + } + } + option::iter(maps.last_use_map.find(id)) {|m| ebml_w.tag(c::tag_table_last_use) {|| ebml_w.id(id); @@ -936,6 +943,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt, if tag == (c::tag_table_mutbl as uint) { dcx.maps.mutbl_map.insert(id, ()); + } else if tag == (c::tag_table_copy as uint) { + dcx.maps.copy_map.insert(id, ()); } else { let val_doc = entry_doc[c::tag_table_val]; let val_dsr = ebml::ebml_deserializer(val_doc); diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index 06714050010..d106c2b23d8 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -171,12 +171,28 @@ export check_crate, root_map, mutbl_map; fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, crate: @ast::crate) -> (root_map, mutbl_map) { + + // big hack to keep this off except when I want it on + let msg_level = if tcx.sess.opts.borrowck != 0u { + tcx.sess.opts.borrowck + } else { + os::getenv("RUST_BORROWCK").map_default(0u) { |v| + option::get(uint::from_str(v)) + } + }; + let bccx = @{tcx: tcx, method_map: method_map, + msg_level: msg_level, root_map: root_map(), mutbl_map: int_hash()}; - let req_maps = gather_loans::gather_loans(bccx, crate); + let req_maps = if msg_level > 0u { + gather_loans::gather_loans(bccx, crate) + } else { + {req_loan_map: int_hash(), + pure_map: int_hash()} + }; check_loans::check_loans(bccx, req_maps, crate); ret (bccx.root_map, bccx.mutbl_map); } @@ -186,6 +202,7 @@ fn check_crate(tcx: ty::ctxt, type borrowck_ctxt = @{tcx: ty::ctxt, method_map: typeck::method_map, + msg_level: uint, root_map: root_map, mutbl_map: mutbl_map}; @@ -346,7 +363,11 @@ impl error_methods for borrowck_ctxt { } fn span_err(s: span, m: str) { - self.tcx.sess.span_err(s, m); + if self.msg_level == 1u { + self.tcx.sess.span_warn(s, m); + } else { + self.tcx.sess.span_err(s, m); + } } fn span_note(s: span, m: str) { diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index 44f26ad6947..f31f3a209bc 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -614,7 +614,25 @@ fn make_phi_bindings(bcx: block, map: [exit_node], bcx.fcx.lllocals.insert(node_id, local_mem(local)); } else { success = false; } }; - if !success { + if success { + // Copy references that the alias analysis considered unsafe + for ids.each_value {|node_id| + if bcx.ccx().maps.copy_map.contains_key(node_id) { + let local = alt bcx.fcx.lllocals.find(node_id) { + some(local_mem(x)) { x } + _ { bcx.tcx().sess.bug("someone \ + forgot to document an invariant in \ + make_phi_bindings"); } + }; + let e_ty = node_id_type(bcx, node_id); + let alloc = alloc_ty(bcx, e_ty); + bcx = copy_val(bcx, INIT, alloc, + load_if_immediate(bcx, local, e_ty), e_ty); + add_clean(bcx, alloc, e_ty); + bcx.fcx.lllocals.insert(node_id, local_mem(alloc)); + } + }; + } else { Unreachable(bcx); } ret success; @@ -701,7 +719,7 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, alt pat.node { ast::pat_ident(_,inner) { if pat_is_variant(bcx.tcx().def_map, pat) { ret bcx; } - if make_copy { + if make_copy || ccx.maps.copy_map.contains_key(pat.id) { let ty = node_id_type(bcx, pat.id); let llty = type_of::type_of(ccx, ty); let alloc = alloca(bcx, llty); diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 93f659dfccf..34845ceb45a 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2888,11 +2888,22 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr, // to have type lldestty (the callee's expected type). val = llvm::LLVMGetUndef(lldestty); } else if arg_mode == ast::by_ref || arg_mode == ast::by_val { + let mut copied = false; let imm = ty::type_is_immediate(arg.ty); #debug[" arg.ty=%s, imm=%b, arg_mode=%?, lv.kind=%?", ty_to_str(bcx.tcx(), arg.ty), imm, arg_mode, lv.kind]; if arg_mode == ast::by_ref && lv.kind != owned && imm { val = do_spill_noroot(bcx, val); + copied = true; + } + if ccx.maps.copy_map.contains_key(e.id) && lv.kind != temporary { + if !copied { + let alloc = alloc_ty(bcx, arg.ty); + bcx = copy_val(bcx, INIT, alloc, + load_if_immediate(bcx, val, arg.ty), arg.ty); + val = alloc; + } else { bcx = take_ty(bcx, val, arg.ty); } + add_clean(bcx, val, arg.ty); } if arg_mode == ast::by_val && (lv.kind == owned || !imm) { val = Load(bcx, val); diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs index c0007b0a13f..cf929353ab4 100644 --- a/src/rustc/middle/trans/reflect.rs +++ b/src/rustc/middle/trans/reflect.rs @@ -19,13 +19,11 @@ enum reflector = { impl methods for reflector { fn c_uint(u: uint) -> ValueRef { - let bcx = self.bcx; - C_uint(bcx.ccx(), u) + C_uint(self.bcx.ccx(), u) } fn visit(ty_name: str, args: [ValueRef]) { - let bcx = self.bcx; - let tcx = bcx.tcx(); + let tcx = self.bcx.tcx(); let mth_idx = option::get(ty::method_idx("visit_" + ty_name, *self.visitor_methods)); let mth_ty = ty::mk_fn(tcx, self.visitor_methods[mth_idx].fty); diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 7d112ae7146..7cdaeb9273b 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -78,6 +78,7 @@ mod middle { mod loan; mod preserve; } + mod alias; mod liveness; mod block_use; mod kind; diff --git a/src/test/compile-fail/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck-assign-comp-idx.rs index a83f727369e..c418c855237 100644 --- a/src/test/compile-fail/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck-assign-comp-idx.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + type point = { x: int, y: int }; fn a() { diff --git a/src/test/compile-fail/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck-assign-comp.rs index 2e045b84c60..c8830957c76 100644 --- a/src/test/compile-fail/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck-assign-comp.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + type point = { x: int, y: int }; fn a() { diff --git a/src/test/compile-fail/borrowck-lend-args.rs b/src/test/compile-fail/borrowck-lend-args.rs index ef8914b134f..aa2358121e2 100644 --- a/src/test/compile-fail/borrowck-lend-args.rs +++ b/src/test/compile-fail/borrowck-lend-args.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn borrow(_v: &int) {} fn borrow_from_arg_imm_ref(&&v: ~int) { diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index e3916867412..def99033e5e 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + // Note: the borrowck analysis is currently flow-insensitive. // Therefore, some of these errors are marked as spurious and could be // corrected by a simple change to the analysis. The others are diff --git a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs index 0862af2e6fa..d9f3bd05676 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn borrow(v: &int, f: fn(x: &int)) { f(v); } diff --git a/src/test/compile-fail/borrowck-loan-blocks-move.rs b/src/test/compile-fail/borrowck-loan-blocks-move.rs index b5044754ac0..6c26aafd425 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn take(-_v: ~int) { } diff --git a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs index 186229f39bd..d7538f168ab 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn borrow(v: &int, f: fn(x: &int)) { f(v); } diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index a268b37ca72..7f45a50cbf4 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + type point = { x: int, y: int }; impl foo for point { diff --git a/src/test/compile-fail/borrowck-loan-rcvr.rs b/src/test/compile-fail/borrowck-loan-rcvr.rs index ec543bfc4f9..1fba825d5ab 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + type point = { x: int, y: int }; impl foo for point { diff --git a/src/test/compile-fail/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck-loan-vec-content.rs index 80e23570a0d..c3d0a62f05e 100644 --- a/src/test/compile-fail/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck-loan-vec-content.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + // Here we check that it is allowed to lend out an element of a // (locally rooted) mutable, unique vector, and that we then prevent // modifications to the contents. diff --git a/src/test/compile-fail/borrowck-mut-vec-as-imm-slice-bad.rs b/src/test/compile-fail/borrowck-mut-vec-as-imm-slice-bad.rs index c14c35189b5..803f30f8e33 100644 --- a/src/test/compile-fail/borrowck-mut-vec-as-imm-slice-bad.rs +++ b/src/test/compile-fail/borrowck-mut-vec-as-imm-slice-bad.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn want_slice(v: [int]/&) -> int { let mut sum = 0; for vec::each(v) { |i| sum += i; } diff --git a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs b/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs deleted file mode 100644 index a546ef867e1..00000000000 --- a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs +++ /dev/null @@ -1,13 +0,0 @@ -enum cycle { - node({mut a: ~cycle}), - empty -} -fn main() { - let x = ~node({mut a: ~empty}); - // Create a cycle! - alt check *x { //! NOTE loan of immutable local variable granted here - node(y) { - y.a <- x; //! ERROR moving out of immutable local variable prohibited due to outstanding loan - } - }; -} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-pat-enum-in-box.rs b/src/test/compile-fail/borrowck-pat-enum-in-box.rs index 29de06a1104..32135b5ad8f 100644 --- a/src/test/compile-fail/borrowck-pat-enum-in-box.rs +++ b/src/test/compile-fail/borrowck-pat-enum-in-box.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn match_imm_box(v: &const @option<int>) -> int { alt *v { @some(i) {i} diff --git a/src/test/compile-fail/borrowck-pat-enum.rs b/src/test/compile-fail/borrowck-pat-enum.rs index 8e87e5d7420..753b51b0251 100644 --- a/src/test/compile-fail/borrowck-pat-enum.rs +++ b/src/test/compile-fail/borrowck-pat-enum.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn match_ref(&&v: option<int>) -> int { alt v { some(i) { diff --git a/src/test/compile-fail/borrowck-pat-reassign-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-binding.rs index cf1199557bd..5018d4835ae 100644 --- a/src/test/compile-fail/borrowck-pat-reassign-binding.rs +++ b/src/test/compile-fail/borrowck-pat-reassign-binding.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // xfail-pretty -- comments are infaithfully preserved fn main() { diff --git a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs index db8129d005a..bf28af2db4d 100644 --- a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs +++ b/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // xfail-pretty -- comments are infaithfully preserved fn main() { diff --git a/src/test/compile-fail/borrowck-pure-scope-in-call.rs b/src/test/compile-fail/borrowck-pure-scope-in-call.rs index 4469dca3620..9e83fd4be35 100644 --- a/src/test/compile-fail/borrowck-pure-scope-in-call.rs +++ b/src/test/compile-fail/borrowck-pure-scope-in-call.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + pure fn pure_borrow(_x: &int, _y: ()) {} fn test1(x: @mut ~int) { diff --git a/src/test/compile-fail/borrowck-unchecked-with-borrow.rs b/src/test/compile-fail/borrowck-unchecked-with-borrow.rs index a5f8b947bf2..cefe3ba0553 100644 --- a/src/test/compile-fail/borrowck-unchecked-with-borrow.rs +++ b/src/test/compile-fail/borrowck-unchecked-with-borrow.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn impure(_i: int) {} // check that unchecked alone does not override borrowck: diff --git a/src/test/compile-fail/borrowck-uniq-via-box.rs b/src/test/compile-fail/borrowck-uniq-via-box.rs index cf0f5439afc..4433dba0c19 100644 --- a/src/test/compile-fail/borrowck-uniq-via-box.rs +++ b/src/test/compile-fail/borrowck-uniq-via-box.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn borrow(_v: &int) {} fn box_mut(v: @mut ~int) { diff --git a/src/test/compile-fail/borrowck-uniq-via-lend.rs b/src/test/compile-fail/borrowck-uniq-via-lend.rs index 78bba1576e8..787285e7bf5 100644 --- a/src/test/compile-fail/borrowck-uniq-via-lend.rs +++ b/src/test/compile-fail/borrowck-uniq-via-lend.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn borrow(_v: &int) {} fn local() { diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/compile-fail/borrowck-uniq-via-ref.rs index 156106b880c..b0fae6622d0 100644 --- a/src/test/compile-fail/borrowck-uniq-via-ref.rs +++ b/src/test/compile-fail/borrowck-uniq-via-ref.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err fn borrow(_v: &int) {} fn box_mut(v: &mut ~int) { diff --git a/src/test/compile-fail/issue-511.rs b/src/test/compile-fail/issue-511.rs index 793bb48c79a..40d25a37566 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/compile-fail/issue-511.rs @@ -8,6 +8,8 @@ fn f<T>(&o: option<T>) { fn main() { f::<int>(option::none); //!^ ERROR taking mut reference to static item - //!^^ ERROR illegal borrow unless pure: creating mutable alias to aliasable, immutable memory - //!^^^ NOTE impure due to access to impure function + + // Additional errors reported by borrowck: + //^^ ERROR illegal borrow unless pure: creating mutable alias to aliasable, immutable memory + //^^^ NOTE impure due to access to impure function } \ No newline at end of file diff --git a/src/test/compile-fail/unsafe-alias-2.rs b/src/test/compile-fail/unsafe-alias-2.rs new file mode 100644 index 00000000000..ac20aeec931 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias-2.rs @@ -0,0 +1,8 @@ +// error-pattern:invalidate reference x + +fn whoknows(x: @mut {mut x: int}) { x.x = 10; } + +fn main() { + let box = @mut {mut x: 1}; + alt *box { x { whoknows(box); log(error, x); } } +} diff --git a/src/test/compile-fail/unsafe-alias.rs b/src/test/compile-fail/unsafe-alias.rs new file mode 100644 index 00000000000..0b13c5b5305 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias.rs @@ -0,0 +1,10 @@ +// error-pattern:may alias with argument + +fn foo(x: {mut x: int}, f: fn@()) { log(debug, x); } + +fn whoknows(x: @mut {mut x: int}) { *x = {mut x: 10}; } + +fn main() { + let box = @mut {mut x: 1}; + foo(*box, bind whoknows(box)); +} diff --git a/src/test/compile-fail/unsafe-alt.rs b/src/test/compile-fail/unsafe-alt.rs new file mode 100644 index 00000000000..498508d8980 --- /dev/null +++ b/src/test/compile-fail/unsafe-alt.rs @@ -0,0 +1,8 @@ +// error-pattern:invalidate reference i + +enum foo { left({mut x: int}), right(bool) } + +fn main() { + let mut x = left({mut x: 10}); + alt x { left(i) { x = right(false); copy x; log(debug, i); } _ { } } +} diff --git a/src/test/compile-fail/unsafe-mutable-alias.rs b/src/test/compile-fail/unsafe-mutable-alias.rs new file mode 100644 index 00000000000..1767eb3983c --- /dev/null +++ b/src/test/compile-fail/unsafe-mutable-alias.rs @@ -0,0 +1,8 @@ +// error-pattern:mut reference to a variable that roots another reference + +fn f(a: {mut x: int}, &b: {mut x: int}) -> int { + b.x += 1; + ret a.x + b.x; +} + +fn main() { let i = {mut x: 4}; log(debug, f(i, i)); } diff --git a/src/test/run-pass/alt-implicit-copy-unique.rs b/src/test/run-pass/alt-implicit-copy-unique.rs index bef4af11be4..bffa76efa30 100644 --- a/src/test/run-pass/alt-implicit-copy-unique.rs +++ b/src/test/run-pass/alt-implicit-copy-unique.rs @@ -1,6 +1,6 @@ fn main() { let x = ~{mut a: ~10, b: ~20}; alt x { - ~{a, b} { assert *a == 10; (*x).a = ~30; assert *a == 30; } + ~{a, b} { assert *a == 10; (*x).a = ~30; assert *a == 10; } } } diff --git a/src/test/run-pass/alt-implicit-copy.rs b/src/test/run-pass/alt-implicit-copy.rs index 63cbdf6ca79..43de34e87a8 100644 --- a/src/test/run-pass/alt-implicit-copy.rs +++ b/src/test/run-pass/alt-implicit-copy.rs @@ -1,6 +1,6 @@ fn main() { let x = @{mut a: @10, b: @20}; alt x { - @{a, b} { assert *a == 10; (*x).a = @30; assert *a == 30; } + @{a, b} { assert *a == 10; (*x).a = @30; assert *a == 10; } } } diff --git a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs index a6279d12ab8..e6e4c36db35 100644 --- a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn want_slice(v: [int]/&) -> int { let mut sum = 0; for vec::each(v) { |i| sum += i; } diff --git a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs index 73a7085d865..e5dd8a1756c 100644 --- a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs +++ b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs @@ -1,3 +1,6 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err + fn main() { let mut x = none; alt x { diff --git a/src/test/run-pass/borrowck-preserve-box-in-arm-not-taken.rs b/src/test/run-pass/borrowck-preserve-box-in-arm-not-taken.rs index 9b49e3cd044..5241848131d 100644 --- a/src/test/run-pass/borrowck-preserve-box-in-arm-not-taken.rs +++ b/src/test/run-pass/borrowck-preserve-box-in-arm-not-taken.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn main() { diff --git a/src/test/run-pass/borrowck-preserve-box-in-discr.rs b/src/test/run-pass/borrowck-preserve-box-in-discr.rs index f486ffe557d..044db44595d 100644 --- a/src/test/run-pass/borrowck-preserve-box-in-discr.rs +++ b/src/test/run-pass/borrowck-preserve-box-in-discr.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn main() { diff --git a/src/test/run-pass/borrowck-preserve-box-in-field.rs b/src/test/run-pass/borrowck-preserve-box-in-field.rs index 09353e3d39f..06260dbe5d2 100644 --- a/src/test/run-pass/borrowck-preserve-box-in-field.rs +++ b/src/test/run-pass/borrowck-preserve-box-in-field.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn borrow(x: &int, f: fn(x: &int)) { diff --git a/src/test/run-pass/borrowck-preserve-box-in-pat.rs b/src/test/run-pass/borrowck-preserve-box-in-pat.rs index 0bad47642a0..718507d1efc 100644 --- a/src/test/run-pass/borrowck-preserve-box-in-pat.rs +++ b/src/test/run-pass/borrowck-preserve-box-in-pat.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn main() { diff --git a/src/test/run-pass/borrowck-preserve-box-in-uniq.rs b/src/test/run-pass/borrowck-preserve-box-in-uniq.rs index 475e5eaea8c..3bec4fb083a 100644 --- a/src/test/run-pass/borrowck-preserve-box-in-uniq.rs +++ b/src/test/run-pass/borrowck-preserve-box-in-uniq.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn borrow(x: &int, f: fn(x: &int)) { diff --git a/src/test/run-pass/borrowck-preserve-box-sometimes-needed.rs b/src/test/run-pass/borrowck-preserve-box-sometimes-needed.rs index 285b3ad8e0f..ed6e0b19e01 100644 --- a/src/test/run-pass/borrowck-preserve-box-sometimes-needed.rs +++ b/src/test/run-pass/borrowck-preserve-box-sometimes-needed.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn switcher(x: option<@int>) { diff --git a/src/test/run-pass/borrowck-preserve-box.rs b/src/test/run-pass/borrowck-preserve-box.rs index d4d2f5a2055..ebc1c1ab70d 100644 --- a/src/test/run-pass/borrowck-preserve-box.rs +++ b/src/test/run-pass/borrowck-preserve-box.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn borrow(x: &int, f: fn(x: &int)) { diff --git a/src/test/run-pass/borrowck-preserve-cond-box.rs b/src/test/run-pass/borrowck-preserve-cond-box.rs index 0ee7ce18761..d1098a04d01 100644 --- a/src/test/run-pass/borrowck-preserve-cond-box.rs +++ b/src/test/run-pass/borrowck-preserve-cond-box.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn testfn(cond: bool) { diff --git a/src/test/run-pass/borrowck-preserve-expl-deref.rs b/src/test/run-pass/borrowck-preserve-expl-deref.rs index 0778b895137..c50afeeaa90 100644 --- a/src/test/run-pass/borrowck-preserve-expl-deref.rs +++ b/src/test/run-pass/borrowck-preserve-expl-deref.rs @@ -1,3 +1,5 @@ +// xfail-fast (compile-flags unsupported on windows) +// compile-flags:--borrowck=err // exec-env:RUST_POISON_ON_FREE=1 fn borrow(x: &int, f: fn(x: &int)) { diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 38a7c7e160c..7cd373756f7 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -91,7 +91,7 @@ fn main() { intrinsic::visit_ty::<i16>(vv); intrinsic::visit_ty::<[int]>(vv); - for (copy v.types).each {|s| + for v.types.each {|s| io::println(#fmt("type: %s", s)); } assert v.types == ["bool", "int", "i8", "i16", |
