From 49c6dac47aa93d11b2d4c8deeded4626e23081e7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 5 Jun 2012 15:50:46 -0700 Subject: [PATCH 01/53] rustc: Fix some more cyclic imports --- src/rustc/driver/rustc.rs | 3 ++- src/rustc/metadata/decoder.rs | 2 +- src/rustc/middle/tstate/auxiliary.rs | 5 ++--- src/rustc/middle/ty.rs | 6 +++--- src/rustc/middle/typeck/astconv.rs | 3 ++- src/rustc/middle/typeck/check.rs | 3 ++- src/rustc/util/ppaux.rs | 10 +++++++++- 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/rustc/driver/rustc.rs b/src/rustc/driver/rustc.rs index db185215bea5..5e88df1de5ec 100644 --- a/src/rustc/driver/rustc.rs +++ b/src/rustc/driver/rustc.rs @@ -15,7 +15,8 @@ import std::map::hashmap; import getopts::{opt_present}; import rustc::driver::driver::*; import syntax::codemap; -import rustc::driver::{diagnostic, session}; +import syntax::diagnostic; +import rustc::driver::session; import rustc::middle::lint; import io::reader_util; diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 644d519fc0f2..4df45033a77c 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -7,7 +7,6 @@ import syntax::{ast, ast_util}; import syntax::attr; import middle::ty; import syntax::ast_map; -import common::*; import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, parse_ident}; import syntax::print::pprust; @@ -15,6 +14,7 @@ import cmd=cstore::crate_metadata; import util::ppaux::ty_to_str; import ebml::deserializer; import syntax::diagnostic::span_handler; +import common::*; export class_dtor; export get_class_fields; diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index c34953ac33e6..a41812f72a79 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -13,9 +13,8 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, set_postcondition, ts_ann, clear_in_postcond, clear_in_poststate_}; -import tritv::*; -import bitvectors::promises_; import driver::session::session; +import tritv::{dont_care, tfalse, tritv_get, ttrue}; import syntax::print::pprust::{constr_args_to_str, lit_to_str}; @@ -811,7 +810,7 @@ fn copy_in_poststate_two(fcx: fn_ctxt, src_post: poststate, // dest def_id let insts = find_instances(fcx, subst, val); for insts.each {|p| - if promises_(p.from, src_post) { + if bitvectors::promises_(p.from, src_post) { set_in_poststate_(p.to, target_post); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 3b32bca1e5f8..73f601cf4b06 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -4,19 +4,19 @@ import std::map::hashmap; import driver::session; import session::session; import syntax::{ast, ast_map}; -import syntax::ast::*; import syntax::ast_util; import syntax::ast_util::{is_local, local_def, split_class_items, new_def_hash}; import syntax::codemap::span; import metadata::csearch; -import util::common::*; import util::ppaux::region_to_str; import util::ppaux::vstore_to_str; import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str}; -import syntax::print::pprust::*; import middle::lint::{get_warning_level, vecs_not_implicitly_copyable, ignore}; +import syntax::ast::*; +import syntax::print::pprust::*; + export ty_vid, region_vid, vid; export br_hashmap; export is_instantiable; diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index d8ce3d83a603..476ef9d3ba55 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -45,7 +45,8 @@ an rptr (`&r.T`) use the region `r` that appears in the rptr. "]; import check::fn_ctxt; -import rscope::*; +import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; +import rscope::{in_binding_rscope, region_scope, type_rscope}; iface ast_conv { fn tcx() -> ty::ctxt; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 2649dc6c6756..70167192afc8 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -71,7 +71,8 @@ import collect::{methods}; // ccx.to_ty() import method::{methods}; // methods for method::lookup import middle::ty::tys_in_fn_ty; import regionmanip::{replace_bound_regions_in_fn_ty, region_of}; -import rscope::*; +import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; +import rscope::{in_binding_rscope, region_scope, type_rscope}; type fn_ctxt = // var_bindings, locals and next_var_id are shared diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 60f4ea8dabff..c5c445702d51 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -1,6 +1,14 @@ import std::map::hashmap; import middle::ty; -import middle::ty::*; +import middle::ty::{arg, bound_region, br_anon, br_named, canon_mode}; +import middle::ty::{ck_block, ck_box, ck_uniq, constr, ctxt, field, method}; +import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t}; +import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_constr, ty_enum}; +import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_iface, ty_int}; +import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; +import middle::ty::{ty_ptr, ty_rec, ty_res, ty_rptr, ty_self, ty_str, ty_tup}; +import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral}; +import middle::ty::{ty_vec, vid}; import metadata::encoder; import syntax::codemap; import syntax::print::pprust; From d9cdddeb5f80b11763b6f95fd7eecdef705ed12d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 5 Jun 2012 17:26:52 -0700 Subject: [PATCH 02/53] stdlib: Introduce ord and eq interfaces. Make std::sort::quick_sort3 use them. i=#2348 --- src/libcore/cmp.rs | 10 ++++++++++ src/libcore/core.rc | 2 ++ src/libcore/int-template.rs | 14 ++++++++++++++ src/libcore/uint-template.rs | 14 ++++++++++++++ src/libstd/sort.rs | 13 ++++--------- 5 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/libcore/cmp.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs new file mode 100644 index 000000000000..aea97cf1649f --- /dev/null +++ b/src/libcore/cmp.rs @@ -0,0 +1,10 @@ +#[doc="Interfaces used for comparison."] + +iface ord { + fn lt(&&other: self) -> bool; +} + +iface eq { + fn eq(&&other: self) -> bool; +} + diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 6b4c7ad7d3ca..efcd424024a1 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -44,6 +44,7 @@ export extfmt; export tuple; export to_str; export dvec, dvec_iter; +export cmp; // NDM seems to be necessary for resolve to work export option_iter; @@ -152,6 +153,7 @@ mod tuple; // Ubiquitous-utility-type modules +mod cmp; mod either; mod iter; mod logging; diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 156724cb0617..4011ac1a18a7 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -1,4 +1,5 @@ import T = inst::T; +import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -10,6 +11,7 @@ export range; export compl; export abs; export parse_buf, from_str, to_str, to_str_bytes, str; +export ord, eq; const min_value: T = -1 as T << (inst::bits - 1 as T); const max_value: T = min_value - 1 as T; @@ -108,6 +110,18 @@ fn to_str_bytes(n: T, radix: uint, f: fn([u8]/&) -> U) -> U { #[doc = "Convert to a string"] fn str(i: T) -> str { ret to_str(i, 10u); } +impl ord of ord for T { + fn lt(&&other: T) -> bool { + ret self < other; + } +} + +impl eq of eq for T { + fn eq(&&other: T) -> bool { + ret self == other; + } +} + // FIXME: Has alignment issues on windows and 32-bit linux #[test] diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index a63d01e6e8e0..7126fb3d007d 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -1,4 +1,5 @@ import T = inst::T; +import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -10,6 +11,7 @@ export range; export compl; export to_str, to_str_bytes; export from_str, from_str_radix, str, parse_buf; +export ord, eq; const min_value: T = 0 as T; const max_value: T = 0 as T - 1 as T; @@ -49,6 +51,18 @@ pure fn compl(i: T) -> T { max_value ^ i } +impl ord of ord for T { + fn lt(&&other: T) -> bool { + ret self < other; + } +} + +impl eq of eq for T { + fn eq(&&other: T) -> bool { + ret self == other; + } +} + #[doc = " Parse a buffer of bytes diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 7e16578fd9c8..76c71d7ed2aa 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -1,5 +1,6 @@ #[doc = "Sorting methods"]; import vec::len; +import int::{eq, ord}; export le; export merge_sort; @@ -141,7 +142,6 @@ fn qsort3(compare_func_lt: le, compare_func_eq: le, qsort3::(compare_func_lt, compare_func_eq, arr, i, right); } -// FIXME: This should take lt and eq types (#2348) #[doc = " Fancy quicksort. Sorts a mut vector in place. @@ -152,10 +152,9 @@ According to these slides this is the algorithm of choice for This is an unstable sort. "] -fn quick_sort3(compare_func_lt: le, compare_func_eq: le, - arr: [mut T]) { +fn quick_sort3(arr: [mut T]) { if len::(arr) == 0u { ret; } - qsort3::(compare_func_lt, compare_func_eq, arr, 0, + qsort3::({ |x, y| x.lt(y) }, { |x, y| x.eq(y) }, arr, 0, (len::(arr) as int) - 1); } @@ -163,11 +162,7 @@ fn quick_sort3(compare_func_lt: le, compare_func_eq: le, mod test_qsort3 { fn check_sort(v1: [mut int], v2: [mut int]) { let len = vec::len::(v1); - fn lt(&&a: int, &&b: int) -> bool { ret a < b; } - fn equal(&&a: int, &&b: int) -> bool { ret a == b; } - let f1 = lt; - let f2 = equal; - quick_sort3::(f1, f2, v1); + quick_sort3::(v1); let mut i = 0u; while i < len { log(debug, v2[i]); From 868e3f9180f99ce2d26c84277a644514048d309b Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 5 Jun 2012 16:33:21 -0700 Subject: [PATCH 03/53] Don't try to keep locals off of the stack. Closes #2408. There were bugs in the code path for initialization of non-spilled locals, the code-path is hit approximately never, and mem2reg can do it for us. I think this will let us kill spill_map. --- src/rustc/middle/trans/base.rs | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 1eef30a17826..76a1777ab01f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -3749,6 +3749,8 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block { let ty = expr_ty(bcx, e); let lv = trans_lval(bcx, e); let last_use = (lv.kind == owned && last_use_map.contains_key(e.id)); + #debug["is last use (%s) = %b, %d", expr_to_str(e), last_use, + lv.kind as int]; lval_result_to_dps(lv, ty, last_use, dest) } @@ -4039,29 +4041,10 @@ fn init_local(bcx: block, local: @ast::local) -> block { let ty = node_id_type(bcx, local.node.id); let llptr = alt bcx.fcx.lllocals.find(local.node.id) { some(local_mem(v)) { v } - some(_) { bcx.tcx().sess.span_bug(local.span, + _ { bcx.tcx().sess.span_bug(local.span, "init_local: Someone forgot to document why it's\ safe to assume local.node.init must be local_mem!"); - } - // This is a local that is kept immediate - none { - let initexpr = alt local.node.init { - some({expr, _}) { expr } - none { bcx.tcx().sess.span_bug(local.span, - "init_local: late-initialized var appears to \ - be an immediate -- possibly init_local was called \ - without calling alloc_local"); } - }; - let mut {bcx, val, kind} = trans_temp_lval(bcx, initexpr); - if kind != temporary { - if kind == owned { val = Load(bcx, val); } - let rs = take_ty_immediate(bcx, val, ty); - bcx = rs.bcx; val = rs.val; - add_clean_temp(bcx, val, ty); } - bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val)); - ret bcx; - } }; let mut bcx = bcx; @@ -4341,17 +4324,6 @@ fn alloc_local(cx: block, local: @ast::local) -> block { ast::pat_ident(pth, none) { some(path_to_ident(pth)) } _ { none } }; - // Do not allocate space for locals that can be kept immediate. - let ccx = cx.ccx(); - if option::is_some(simple_name) && - !ccx.maps.mutbl_map.contains_key(local.node.pat.id) && - !ccx.maps.spill_map.contains_key(local.node.pat.id) && - ty::type_is_immediate(t) { - alt local.node.init { - some({op: ast::init_assign, _}) { ret cx; } - _ {} - } - } let val = alloc_ty(cx, t); if cx.sess().opts.debuginfo { option::iter(simple_name) {|name| From 167d72618371b7f7dd75df7c5a5b1375d1823a3d Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 5 Jun 2012 17:29:36 -0700 Subject: [PATCH 04/53] Get rid of spill_map and associated infrastructure. --- src/rustc/driver/driver.rs | 4 +-- src/rustc/middle/astencode.rs | 9 ------ src/rustc/middle/liveness.rs | 61 ++++++----------------------------- 3 files changed, 11 insertions(+), 63 deletions(-) diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 6d4f48595d25..e769455376a5 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -194,7 +194,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, spill_map) = + let last_use_map = time(time_passes, "liveness checking", bind middle::liveness::check_crate(ty_cx, method_map, crate)); time(time_passes, "typestate checking", @@ -216,7 +216,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let maps = {mutbl_map: mutbl_map, root_map: root_map, 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}; + vtable_map: vtable_map}; let (llmod, link_meta) = time(time_passes, "translation", diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 2fd59cb21662..6ebf0ed9ec65 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -57,7 +57,6 @@ type maps = { impl_map: middle::resolve::impl_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, - spill_map: middle::liveness::spill_map }; type decode_ctxt = @{ @@ -839,12 +838,6 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, } } - option::iter(maps.spill_map.find(id)) {|_m| - ebml_w.tag(c::tag_table_spill) {|| - 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); @@ -953,8 +946,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt, dcx.maps.mutbl_map.insert(id, ()); } else if tag == (c::tag_table_copy as uint) { dcx.maps.copy_map.insert(id, ()); - } else if tag == (c::tag_table_spill as uint) { - dcx.maps.spill_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/liveness.rs b/src/rustc/middle/liveness.rs index 3f82e647ab6b..048823f4553f 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -57,7 +57,6 @@ 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 @@ -66,13 +65,6 @@ export spill_map; // list of closed over variables that can be moved into the closure. type last_use_map = hashmap>; -// A set of variable ids which must be spilled (stored on the stack). -// We add in any variables or arguments where: -// (1) the variables are moved; -// (2) the address of the variable/argument is taken; -// or (3) we find a last use (as they may be moved). -type spill_map = hashmap; - enum variable = uint; enum live_node = uint; @@ -85,7 +77,7 @@ enum live_node_kind { fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - crate: @crate) -> (last_use_map, spill_map) { + crate: @crate) -> last_use_map { let visitor = visit::mk_vt(@{ visit_fn: visit_fn, visit_local: visit_local, @@ -94,12 +86,11 @@ fn check_crate(tcx: ty::ctxt, }); let last_use_map = int_hash(); - let spill_map = int_hash(); let initial_maps = @ir_maps(tcx, method_map, - last_use_map, spill_map); + last_use_map); visit::visit_crate(*crate, initial_maps, visitor); tcx.sess.abort_if_errors(); - ret (last_use_map, spill_map); + ret last_use_map; } impl of to_str::to_str for live_node { @@ -162,7 +153,6 @@ class ir_maps { let tcx: ty::ctxt; let method_map: typeck::method_map; let last_use_map: last_use_map; - let spill_map: spill_map; let mut num_live_nodes: uint; let mut num_vars: uint; @@ -174,11 +164,10 @@ class ir_maps { let mut lnks: [live_node_kind]; new(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: last_use_map, spill_map: spill_map) { + last_use_map: last_use_map) { self.tcx = tcx; self.method_map = method_map; self.last_use_map = last_use_map; - self.spill_map = spill_map; self.num_live_nodes = 0u; self.num_vars = 0u; @@ -264,17 +253,6 @@ class ir_maps { self.lnks[*ln] } - 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, ()); - } - vk_arg(*) | vk_field(_) | vk_self | vk_implicit_ret {} - } - } - 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]; @@ -308,7 +286,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, // swap in a new set of IR maps for this function body: let fn_maps = @ir_maps(self.tcx, self.method_map, - self.last_use_map, self.spill_map); + self.last_use_map); #debug["creating fn_maps: %x", ptr::addr_of(*fn_maps) as uint]; @@ -1407,11 +1385,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { vt.visit_expr(f, self, vt); vec::iter2(args, targs) { |arg_expr, arg_ty| alt ty::resolved_mode(self.tcx, arg_ty.mode) { - by_val | by_copy { - vt.visit_expr(arg_expr, self, vt); - } - by_ref | by_mutbl_ref { - self.spill_expr(arg_expr); + by_val | by_copy | by_ref | by_mutbl_ref{ vt.visit_expr(arg_expr, self, vt); } by_move { @@ -1421,10 +1395,6 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { } } - expr_addr_of(_, arg_expr) { - self.spill_expr(arg_expr); - } - // no correctness conditions related to liveness expr_if_check(*) | expr_if(*) | expr_alt(*) | expr_while(*) | expr_loop(*) | @@ -1434,7 +1404,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { expr_assert(*) | expr_check(*) | expr_copy(*) | expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) | expr_ret(*) | expr_break | expr_cont | expr_lit(_) | - expr_block(*) | expr_swap(*) | expr_mac(*) { + expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) { visit::visit_expr(expr, self, vt); } } @@ -1501,10 +1471,7 @@ impl check_methods for @liveness { ln.to_str(), var.to_str()]; alt (*self).live_on_exit(ln, var) { - none { - // update spill map to include this variable, as it is moved: - (*self.ir).add_spill(var); - } + none { } some(lnk) { self.report_illegal_move(span, lnk, var); } @@ -1516,20 +1483,10 @@ impl check_methods for @liveness { some(_) {} none { (*self.ir).add_last_use(expr.id, var); - - // update spill map to include this variable, as it may be moved: - (*self.ir).add_spill(var); } } } - fn spill_expr(expr: @expr) { - alt (*self).variable_from_path(expr) { - some(var) {(*self.ir).add_spill(var)} - none {} - } - } - fn check_move_from_expr(expr: @expr, vt: vt<@liveness>) { #debug["check_move_from_expr(node %d: %s)", expr.id, expr_to_str(expr)]; @@ -1775,4 +1732,4 @@ impl check_methods for @liveness { } } } - } \ No newline at end of file + } From 8fd9986f0ff1d0414cc064451f72748065a77cdf Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 5 Jun 2012 20:46:10 -0700 Subject: [PATCH 05/53] Forbid classes with no fields Classes with no fields don't really make sense, so forbid them (just as records with no fields aren't allowed). Closes #2509 --- src/rustc/middle/typeck/check.rs | 6 ++++++ src/test/compile-fail/issue-2509-a.rs | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/compile-fail/issue-2509-a.rs diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 70167192afc8..b3f7c5a93885 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -387,6 +387,12 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { }; // typecheck the members for members.each {|m| check_class_member(class_ccx, class_t, m); } + // Check that there's at least one field + let (fields,_) = split_class_items(members); + if fields.len() < 1u { + ccx.tcx.sess.span_err(it.span, "A class must have at least one \ + field"); + } // Check that the class is instantiable check_instantiable(ccx.tcx, it.span, it.id); } diff --git a/src/test/compile-fail/issue-2509-a.rs b/src/test/compile-fail/issue-2509-a.rs new file mode 100644 index 000000000000..a500d249c07a --- /dev/null +++ b/src/test/compile-fail/issue-2509-a.rs @@ -0,0 +1,9 @@ +class c { //! ERROR A class must have at least one field + new() { } +} + +fn main() { + let a = c(); + let x = [a]; + let _y = x[0]; +} From 17e707cf6dc8cfa1b006c86f1d9d690f9f825654 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 5 Jun 2012 21:13:25 -0700 Subject: [PATCH 06/53] Fix test case so the class in it is non-empty --- src/test/run-pass/conditional-compile.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 8f4bd22f75dd..2b64840d8301 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -26,11 +26,13 @@ enum tg { bar, } #[cfg(bogus)] class r { - new(i:int) {} + let i: int; + new(i:int) { self.i = i; } } class r { - new(i:int) {} + let i: int; + new(i:int) { self.i = i; } } #[cfg(bogus)] From e8493115c5f7709ccefb1fd3b6f595746a9d8319 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 5 Jun 2012 21:40:57 -0700 Subject: [PATCH 07/53] Switch "make all" to build stage2 versions of fuzzer, cargo, and rustdoc This should trim some time off "make all" because it doesn't force the stage3 rustc to be built. Even better, we can directly use the cargo out of the build directory because we automatically build the stage2 libcore and libstd. --- Makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index b657ad6a6883..df9cb78ef8f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -421,9 +421,9 @@ else TSREQS := \ $(foreach target,$(CFG_TARGET_TRIPLES), \ $(SREQ3_T_$(target)_H_$(CFG_HOST_TRIPLE))) -FUZZ := $(HBIN3_H_$(CFG_HOST_TRIPLE))/fuzzer$(X) -CARGO := $(HBIN3_H_$(CFG_HOST_TRIPLE))/cargo$(X) -RUSTDOC := $(HBIN3_H_$(CFG_HOST_TRIPLE))/rustdoc$(X) +FUZZ := $(HBIN2_H_$(CFG_HOST_TRIPLE))/fuzzer$(X) +CARGO := $(HBIN2_H_$(CFG_HOST_TRIPLE))/cargo$(X) +RUSTDOC := $(HBIN2_H_$(CFG_HOST_TRIPLE))/rustdoc$(X) all: rustc $(GENERATED) docs $(FUZZ) $(CARGO) $(RUSTDOC) From 055158d05191000384b490399c104394cbc0c838 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:39:00 -0700 Subject: [PATCH 08/53] Revert "Merge pull request #2516 from mozilla/incoming" due to failures This reverts commit adb717b5fa3500c50ced39266c76fc909808c189, reversing changes made to aabf84cdd81351cc63ebdc9e2427203621d19950. --- src/libcore/cmp.rs | 10 ---- src/libcore/core.rc | 2 - src/libcore/int-template.rs | 14 ------ src/libcore/uint-template.rs | 14 ------ src/libstd/sort.rs | 13 +++-- src/rustc/driver/driver.rs | 4 +- src/rustc/driver/rustc.rs | 3 +- src/rustc/metadata/decoder.rs | 2 +- src/rustc/middle/astencode.rs | 9 ++++ src/rustc/middle/liveness.rs | 61 ++++++++++++++++++++---- src/rustc/middle/trans/base.rs | 34 +++++++++++-- src/rustc/middle/tstate/auxiliary.rs | 5 +- src/rustc/middle/ty.rs | 6 +-- src/rustc/middle/typeck/astconv.rs | 3 +- src/rustc/middle/typeck/check.rs | 9 +--- src/rustc/util/ppaux.rs | 10 +--- src/test/compile-fail/issue-2509-a.rs | 9 ---- src/test/run-pass/conditional-compile.rs | 6 +-- 18 files changed, 116 insertions(+), 98 deletions(-) delete mode 100644 src/libcore/cmp.rs delete mode 100644 src/test/compile-fail/issue-2509-a.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs deleted file mode 100644 index aea97cf1649f..000000000000 --- a/src/libcore/cmp.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[doc="Interfaces used for comparison."] - -iface ord { - fn lt(&&other: self) -> bool; -} - -iface eq { - fn eq(&&other: self) -> bool; -} - diff --git a/src/libcore/core.rc b/src/libcore/core.rc index efcd424024a1..6b4c7ad7d3ca 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -44,7 +44,6 @@ export extfmt; export tuple; export to_str; export dvec, dvec_iter; -export cmp; // NDM seems to be necessary for resolve to work export option_iter; @@ -153,7 +152,6 @@ mod tuple; // Ubiquitous-utility-type modules -mod cmp; mod either; mod iter; mod logging; diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 4011ac1a18a7..156724cb0617 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -1,5 +1,4 @@ import T = inst::T; -import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -11,7 +10,6 @@ export range; export compl; export abs; export parse_buf, from_str, to_str, to_str_bytes, str; -export ord, eq; const min_value: T = -1 as T << (inst::bits - 1 as T); const max_value: T = min_value - 1 as T; @@ -110,18 +108,6 @@ fn to_str_bytes(n: T, radix: uint, f: fn([u8]/&) -> U) -> U { #[doc = "Convert to a string"] fn str(i: T) -> str { ret to_str(i, 10u); } -impl ord of ord for T { - fn lt(&&other: T) -> bool { - ret self < other; - } -} - -impl eq of eq for T { - fn eq(&&other: T) -> bool { - ret self == other; - } -} - // FIXME: Has alignment issues on windows and 32-bit linux #[test] diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index 7126fb3d007d..a63d01e6e8e0 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -1,5 +1,4 @@ import T = inst::T; -import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -11,7 +10,6 @@ export range; export compl; export to_str, to_str_bytes; export from_str, from_str_radix, str, parse_buf; -export ord, eq; const min_value: T = 0 as T; const max_value: T = 0 as T - 1 as T; @@ -51,18 +49,6 @@ pure fn compl(i: T) -> T { max_value ^ i } -impl ord of ord for T { - fn lt(&&other: T) -> bool { - ret self < other; - } -} - -impl eq of eq for T { - fn eq(&&other: T) -> bool { - ret self == other; - } -} - #[doc = " Parse a buffer of bytes diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 76c71d7ed2aa..7e16578fd9c8 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -1,6 +1,5 @@ #[doc = "Sorting methods"]; import vec::len; -import int::{eq, ord}; export le; export merge_sort; @@ -142,6 +141,7 @@ fn qsort3(compare_func_lt: le, compare_func_eq: le, qsort3::(compare_func_lt, compare_func_eq, arr, i, right); } +// FIXME: This should take lt and eq types (#2348) #[doc = " Fancy quicksort. Sorts a mut vector in place. @@ -152,9 +152,10 @@ According to these slides this is the algorithm of choice for This is an unstable sort. "] -fn quick_sort3(arr: [mut T]) { +fn quick_sort3(compare_func_lt: le, compare_func_eq: le, + arr: [mut T]) { if len::(arr) == 0u { ret; } - qsort3::({ |x, y| x.lt(y) }, { |x, y| x.eq(y) }, arr, 0, + qsort3::(compare_func_lt, compare_func_eq, arr, 0, (len::(arr) as int) - 1); } @@ -162,7 +163,11 @@ fn quick_sort3(arr: [mut T]) { mod test_qsort3 { fn check_sort(v1: [mut int], v2: [mut int]) { let len = vec::len::(v1); - quick_sort3::(v1); + fn lt(&&a: int, &&b: int) -> bool { ret a < b; } + fn equal(&&a: int, &&b: int) -> bool { ret a == b; } + let f1 = lt; + let f2 = equal; + quick_sort3::(f1, f2, v1); let mut i = 0u; while i < len { log(debug, v2[i]); diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index e769455376a5..6d4f48595d25 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -194,7 +194,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", @@ -216,7 +216,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let maps = {mutbl_map: mutbl_map, root_map: root_map, copy_map: copy_map, last_use_map: last_use_map, impl_map: impl_map, method_map: method_map, - vtable_map: vtable_map}; + vtable_map: vtable_map, spill_map: spill_map}; let (llmod, link_meta) = time(time_passes, "translation", diff --git a/src/rustc/driver/rustc.rs b/src/rustc/driver/rustc.rs index 5e88df1de5ec..db185215bea5 100644 --- a/src/rustc/driver/rustc.rs +++ b/src/rustc/driver/rustc.rs @@ -15,8 +15,7 @@ import std::map::hashmap; import getopts::{opt_present}; import rustc::driver::driver::*; import syntax::codemap; -import syntax::diagnostic; -import rustc::driver::session; +import rustc::driver::{diagnostic, session}; import rustc::middle::lint; import io::reader_util; diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 4df45033a77c..644d519fc0f2 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -7,6 +7,7 @@ import syntax::{ast, ast_util}; import syntax::attr; import middle::ty; import syntax::ast_map; +import common::*; import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, parse_ident}; import syntax::print::pprust; @@ -14,7 +15,6 @@ import cmd=cstore::crate_metadata; import util::ppaux::ty_to_str; import ebml::deserializer; import syntax::diagnostic::span_handler; -import common::*; export class_dtor; export get_class_fields; diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 6ebf0ed9ec65..2fd59cb21662 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -57,6 +57,7 @@ type maps = { impl_map: middle::resolve::impl_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, + spill_map: middle::liveness::spill_map }; type decode_ctxt = @{ @@ -838,6 +839,12 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, } } + option::iter(maps.spill_map.find(id)) {|_m| + ebml_w.tag(c::tag_table_spill) {|| + 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); @@ -946,6 +953,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt, dcx.maps.mutbl_map.insert(id, ()); } else if tag == (c::tag_table_copy as uint) { dcx.maps.copy_map.insert(id, ()); + } else if tag == (c::tag_table_spill as uint) { + dcx.maps.spill_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/liveness.rs b/src/rustc/middle/liveness.rs index 048823f4553f..3f82e647ab6b 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 @@ -65,6 +66,13 @@ export last_use_map; // list of closed over variables that can be moved into the closure. type last_use_map = hashmap>; +// A set of variable ids which must be spilled (stored on the stack). +// We add in any variables or arguments where: +// (1) the variables are moved; +// (2) the address of the variable/argument is taken; +// or (3) we find a last use (as they may be moved). +type spill_map = hashmap; + enum variable = uint; enum live_node = uint; @@ -77,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, @@ -86,11 +94,12 @@ fn check_crate(tcx: ty::ctxt, }); let last_use_map = int_hash(); + let spill_map = int_hash(); let initial_maps = @ir_maps(tcx, method_map, - last_use_map); + 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 { @@ -153,6 +162,7 @@ class ir_maps { let tcx: ty::ctxt; let method_map: typeck::method_map; let last_use_map: last_use_map; + let spill_map: spill_map; let mut num_live_nodes: uint; let mut num_vars: uint; @@ -164,10 +174,11 @@ class ir_maps { let mut lnks: [live_node_kind]; new(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: last_use_map) { + last_use_map: last_use_map, spill_map: spill_map) { self.tcx = tcx; self.method_map = method_map; self.last_use_map = last_use_map; + self.spill_map = spill_map; self.num_live_nodes = 0u; self.num_vars = 0u; @@ -253,6 +264,17 @@ class ir_maps { self.lnks[*ln] } + 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, ()); + } + vk_arg(*) | vk_field(_) | vk_self | vk_implicit_ret {} + } + } + 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]; @@ -286,7 +308,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, // swap in a new set of IR maps for this function body: let fn_maps = @ir_maps(self.tcx, self.method_map, - self.last_use_map); + self.last_use_map, self.spill_map); #debug["creating fn_maps: %x", ptr::addr_of(*fn_maps) as uint]; @@ -1385,7 +1407,11 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { vt.visit_expr(f, self, vt); vec::iter2(args, targs) { |arg_expr, arg_ty| alt ty::resolved_mode(self.tcx, arg_ty.mode) { - by_val | by_copy | by_ref | by_mutbl_ref{ + by_val | by_copy { + vt.visit_expr(arg_expr, self, vt); + } + by_ref | by_mutbl_ref { + self.spill_expr(arg_expr); vt.visit_expr(arg_expr, self, vt); } by_move { @@ -1395,6 +1421,10 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { } } + expr_addr_of(_, arg_expr) { + self.spill_expr(arg_expr); + } + // no correctness conditions related to liveness expr_if_check(*) | expr_if(*) | expr_alt(*) | expr_while(*) | expr_loop(*) | @@ -1404,7 +1434,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { expr_assert(*) | expr_check(*) | expr_copy(*) | expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) | expr_ret(*) | expr_break | expr_cont | expr_lit(_) | - expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) { + expr_block(*) | expr_swap(*) | expr_mac(*) { visit::visit_expr(expr, self, vt); } } @@ -1471,7 +1501,10 @@ impl check_methods for @liveness { ln.to_str(), var.to_str()]; alt (*self).live_on_exit(ln, var) { - none { } + none { + // update spill map to include this variable, as it is moved: + (*self.ir).add_spill(var); + } some(lnk) { self.report_illegal_move(span, lnk, var); } @@ -1483,10 +1516,20 @@ impl check_methods for @liveness { some(_) {} none { (*self.ir).add_last_use(expr.id, var); + + // update spill map to include this variable, as it may be moved: + (*self.ir).add_spill(var); } } } + fn spill_expr(expr: @expr) { + alt (*self).variable_from_path(expr) { + some(var) {(*self.ir).add_spill(var)} + none {} + } + } + fn check_move_from_expr(expr: @expr, vt: vt<@liveness>) { #debug["check_move_from_expr(node %d: %s)", expr.id, expr_to_str(expr)]; @@ -1732,4 +1775,4 @@ impl check_methods for @liveness { } } } - } + } \ No newline at end of file diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 76a1777ab01f..1eef30a17826 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -3749,8 +3749,6 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block { let ty = expr_ty(bcx, e); let lv = trans_lval(bcx, e); let last_use = (lv.kind == owned && last_use_map.contains_key(e.id)); - #debug["is last use (%s) = %b, %d", expr_to_str(e), last_use, - lv.kind as int]; lval_result_to_dps(lv, ty, last_use, dest) } @@ -4041,10 +4039,29 @@ fn init_local(bcx: block, local: @ast::local) -> block { let ty = node_id_type(bcx, local.node.id); let llptr = alt bcx.fcx.lllocals.find(local.node.id) { some(local_mem(v)) { v } - _ { bcx.tcx().sess.span_bug(local.span, + some(_) { bcx.tcx().sess.span_bug(local.span, "init_local: Someone forgot to document why it's\ safe to assume local.node.init must be local_mem!"); + } + // This is a local that is kept immediate + none { + let initexpr = alt local.node.init { + some({expr, _}) { expr } + none { bcx.tcx().sess.span_bug(local.span, + "init_local: late-initialized var appears to \ + be an immediate -- possibly init_local was called \ + without calling alloc_local"); } + }; + let mut {bcx, val, kind} = trans_temp_lval(bcx, initexpr); + if kind != temporary { + if kind == owned { val = Load(bcx, val); } + let rs = take_ty_immediate(bcx, val, ty); + bcx = rs.bcx; val = rs.val; + add_clean_temp(bcx, val, ty); } + bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val)); + ret bcx; + } }; let mut bcx = bcx; @@ -4324,6 +4341,17 @@ fn alloc_local(cx: block, local: @ast::local) -> block { ast::pat_ident(pth, none) { some(path_to_ident(pth)) } _ { none } }; + // Do not allocate space for locals that can be kept immediate. + let ccx = cx.ccx(); + if option::is_some(simple_name) && + !ccx.maps.mutbl_map.contains_key(local.node.pat.id) && + !ccx.maps.spill_map.contains_key(local.node.pat.id) && + ty::type_is_immediate(t) { + alt local.node.init { + some({op: ast::init_assign, _}) { ret cx; } + _ {} + } + } let val = alloc_ty(cx, t); if cx.sess().opts.debuginfo { option::iter(simple_name) {|name| diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index a41812f72a79..c34953ac33e6 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -13,8 +13,9 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, set_postcondition, ts_ann, clear_in_postcond, clear_in_poststate_}; +import tritv::*; +import bitvectors::promises_; import driver::session::session; -import tritv::{dont_care, tfalse, tritv_get, ttrue}; import syntax::print::pprust::{constr_args_to_str, lit_to_str}; @@ -810,7 +811,7 @@ fn copy_in_poststate_two(fcx: fn_ctxt, src_post: poststate, // dest def_id let insts = find_instances(fcx, subst, val); for insts.each {|p| - if bitvectors::promises_(p.from, src_post) { + if promises_(p.from, src_post) { set_in_poststate_(p.to, target_post); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 73f601cf4b06..3b32bca1e5f8 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -4,19 +4,19 @@ import std::map::hashmap; import driver::session; import session::session; import syntax::{ast, ast_map}; +import syntax::ast::*; import syntax::ast_util; import syntax::ast_util::{is_local, local_def, split_class_items, new_def_hash}; import syntax::codemap::span; import metadata::csearch; +import util::common::*; import util::ppaux::region_to_str; import util::ppaux::vstore_to_str; import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str}; +import syntax::print::pprust::*; import middle::lint::{get_warning_level, vecs_not_implicitly_copyable, ignore}; -import syntax::ast::*; -import syntax::print::pprust::*; - export ty_vid, region_vid, vid; export br_hashmap; export is_instantiable; diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index 476ef9d3ba55..d8ce3d83a603 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -45,8 +45,7 @@ an rptr (`&r.T`) use the region `r` that appears in the rptr. "]; import check::fn_ctxt; -import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; -import rscope::{in_binding_rscope, region_scope, type_rscope}; +import rscope::*; iface ast_conv { fn tcx() -> ty::ctxt; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index b3f7c5a93885..2649dc6c6756 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -71,8 +71,7 @@ import collect::{methods}; // ccx.to_ty() import method::{methods}; // methods for method::lookup import middle::ty::tys_in_fn_ty; import regionmanip::{replace_bound_regions_in_fn_ty, region_of}; -import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; -import rscope::{in_binding_rscope, region_scope, type_rscope}; +import rscope::*; type fn_ctxt = // var_bindings, locals and next_var_id are shared @@ -387,12 +386,6 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { }; // typecheck the members for members.each {|m| check_class_member(class_ccx, class_t, m); } - // Check that there's at least one field - let (fields,_) = split_class_items(members); - if fields.len() < 1u { - ccx.tcx.sess.span_err(it.span, "A class must have at least one \ - field"); - } // Check that the class is instantiable check_instantiable(ccx.tcx, it.span, it.id); } diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index c5c445702d51..60f4ea8dabff 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -1,14 +1,6 @@ import std::map::hashmap; import middle::ty; -import middle::ty::{arg, bound_region, br_anon, br_named, canon_mode}; -import middle::ty::{ck_block, ck_box, ck_uniq, constr, ctxt, field, method}; -import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t}; -import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_constr, ty_enum}; -import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_iface, ty_int}; -import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; -import middle::ty::{ty_ptr, ty_rec, ty_res, ty_rptr, ty_self, ty_str, ty_tup}; -import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral}; -import middle::ty::{ty_vec, vid}; +import middle::ty::*; import metadata::encoder; import syntax::codemap; import syntax::print::pprust; diff --git a/src/test/compile-fail/issue-2509-a.rs b/src/test/compile-fail/issue-2509-a.rs deleted file mode 100644 index a500d249c07a..000000000000 --- a/src/test/compile-fail/issue-2509-a.rs +++ /dev/null @@ -1,9 +0,0 @@ -class c { //! ERROR A class must have at least one field - new() { } -} - -fn main() { - let a = c(); - let x = [a]; - let _y = x[0]; -} diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 2b64840d8301..8f4bd22f75dd 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -26,13 +26,11 @@ enum tg { bar, } #[cfg(bogus)] class r { - let i: int; - new(i:int) { self.i = i; } + new(i:int) {} } class r { - let i: int; - new(i:int) { self.i = i; } + new(i:int) {} } #[cfg(bogus)] From d53e633bd5f9f733fb49ce556d16058baa1453f5 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:39:49 -0700 Subject: [PATCH 09/53] Revert "test: Remove swappable-test" due to test failures This reverts commit aabf84cdd81351cc63ebdc9e2427203621d19950. --- src/test/run-pass/swappable-test.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/run-pass/swappable-test.rs diff --git a/src/test/run-pass/swappable-test.rs b/src/test/run-pass/swappable-test.rs new file mode 100644 index 000000000000..ee3446489017 --- /dev/null +++ b/src/test/run-pass/swappable-test.rs @@ -0,0 +1,13 @@ +import swappable::{swappable, methods}; + +fn main() { + let d = swappable(3); + assert d.get() == 3; + d.set(4); + assert d.get() == 4; + d.swap { |i| i + 1 }; + assert d.get() == 5; + assert d.with { |i| i + 1 } == 6; + assert d.get() == 5; + assert swappable::unwrap(d) == 5; +} \ No newline at end of file From d64ff983110fed10a7a3351ad156091cfaf3203b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:40:04 -0700 Subject: [PATCH 10/53] Revert "core: Remove swappable. Unused" due to test failures This reverts commit ec5cbb4f5e951fcc51362c557b1968a57be36afc. --- src/libcore/core.rc | 2 + src/libcore/swappable.rs | 98 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/libcore/swappable.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 6b4c7ad7d3ca..84cebcceccd8 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -43,6 +43,7 @@ export comm, task, future; export extfmt; export tuple; export to_str; +export swappable; export dvec, dvec_iter; // NDM seems to be necessary for resolve to work @@ -163,6 +164,7 @@ mod option_iter { } mod result; mod to_str; +mod swappable; mod dvec; #[path="iter-trait"] mod dvec_iter { diff --git a/src/libcore/swappable.rs b/src/libcore/swappable.rs new file mode 100644 index 000000000000..5df9b2c48463 --- /dev/null +++ b/src/libcore/swappable.rs @@ -0,0 +1,98 @@ +export swappable; +export unwrap; +export methods; + +#[doc = " +A value that may be swapped out temporarily while it is being processed +and then replaced. Swappables are most useful when working with unique +values, which often cannot be mutated unless they are stored in the local +stack frame to ensure memory safety. + +The type guarantees the invariant that the value is always \"swapped in\" +except during the execution of the `swap()` and `with()` methods. +"] +type swappable = { + mut o_t: option +}; + +#[doc = "Create a swappable swapped in with a given initial value"] +fn swappable(+t: A) -> swappable { + {mut o_t: some(t)} +} + +#[doc = "Consumes a swappable and returns its contents without copying"] +fn unwrap(-s: swappable) -> A { + let {o_t: o_t} <- s; + option::unwrap(o_t) +} + +impl methods for swappable { + #[doc = " + Overwrites the contents of the swappable + "] + fn set(+a: A) { + self.o_t <- some(a); + } + + #[doc = " + Invokes `f()` with the current value but replaces the + current value when complete. Returns the result of `f()`. + + Attempts to read or access the receiver while `f()` is executing + will fail dynamically. + "] + fn with(f: fn(A) -> B) -> B { + let mut o_u = none; + self.swap { |t| o_u <- some(f(t)); t } + option::unwrap(o_u) + } + + #[doc = " + Invokes `f()` with the current value and then replaces the + current value with the result of `f()`. + + Attempts to read or access the receiver while `f()` is executing + will fail dynamically. + "] + fn swap(f: fn(-A) -> A) { + alt self.o_t { + none { fail "no value present---already swapped?"; } + some(_) {} + } + + let mut o_t = none; + o_t <-> self.o_t; + self.o_t <- some(f(option::unwrap(o_t))); + } + + #[doc = "True if there is a value present in this swappable"] + fn is_present() -> bool { + alt self.o_t { + none {false} + some(_) {true} + } + } + + #[doc = " + Removes the value from the swappable. Any further attempts + to use the swapabble without first invoking `set()` will fail. + "] + fn take() -> A { + alt self.o_t { + none { fail "swapped out"; } + some(_) {} + } + + let mut o_t = none; + option::unwrap(o_t) + } +} + +impl methods for swappable { + #[doc = " + Copies out the contents of the swappable + "] + fn get() -> A { + self.o_t.get() + } +} \ No newline at end of file From c6e16c5668a86245259a4f542a62199b2023b89b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:42:53 -0700 Subject: [PATCH 11/53] Revert "Fix test case so the class in it is non-empty" due to test failures This reverts commit 17e707cf6dc8cfa1b006c86f1d9d690f9f825654. --- src/test/run-pass/conditional-compile.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 2b64840d8301..8f4bd22f75dd 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -26,13 +26,11 @@ enum tg { bar, } #[cfg(bogus)] class r { - let i: int; - new(i:int) { self.i = i; } + new(i:int) {} } class r { - let i: int; - new(i:int) { self.i = i; } + new(i:int) {} } #[cfg(bogus)] From e56a6e8cb0ca2be26bb71918447459865803a630 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:43:04 -0700 Subject: [PATCH 12/53] Revert "Forbid classes with no fields" due to test failures This reverts commit 8fd9986f0ff1d0414cc064451f72748065a77cdf. --- src/rustc/middle/typeck/check.rs | 6 ------ src/test/compile-fail/issue-2509-a.rs | 9 --------- 2 files changed, 15 deletions(-) delete mode 100644 src/test/compile-fail/issue-2509-a.rs diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index b3f7c5a93885..70167192afc8 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -387,12 +387,6 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { }; // typecheck the members for members.each {|m| check_class_member(class_ccx, class_t, m); } - // Check that there's at least one field - let (fields,_) = split_class_items(members); - if fields.len() < 1u { - ccx.tcx.sess.span_err(it.span, "A class must have at least one \ - field"); - } // Check that the class is instantiable check_instantiable(ccx.tcx, it.span, it.id); } diff --git a/src/test/compile-fail/issue-2509-a.rs b/src/test/compile-fail/issue-2509-a.rs deleted file mode 100644 index a500d249c07a..000000000000 --- a/src/test/compile-fail/issue-2509-a.rs +++ /dev/null @@ -1,9 +0,0 @@ -class c { //! ERROR A class must have at least one field - new() { } -} - -fn main() { - let a = c(); - let x = [a]; - let _y = x[0]; -} From 704a5a8c681a7e4cb044da9f7b1118baf79b1ff6 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 12:21:35 -0700 Subject: [PATCH 13/53] Register snapshots --- src/snapshots.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index f2000639dbe9..e15145124ff1 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2012-06-05 fec3b91 + winnt-i386 36348a2b016f25d9e3b7e1a8814a352c18123839 + linux-x86_64 7308f0eb3d6a9985c14dfbbde7e1f9eb901cc966 + linux-i386 d4c1e1733fd30945f96ae67dbc10289f2a9ec380 + freebsd-x86_64 d0ee6054d7d8320d64aa4dbb9b041537fa2665d5 + macos-x86_64 652501172b4fee6631f595c90538fd95914ef444 + macos-i386 5c54b5ecf54cc2631fdd48caa326ab44b5a2e494 + S 2012-06-04 7213274 winnt-i386 94b9414433fd83c086b349ded3159f0541aace16 linux-x86_64 eb9cf0de4cc09e8b8bfcf741eff4b20510e13a5b From b54c76c832930c1eab4e1e944117300eacb12625 Mon Sep 17 00:00:00 2001 From: Jyun-Yan You Date: Wed, 6 Jun 2012 11:29:00 +0800 Subject: [PATCH 14/53] fix link error --- src/rustc/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs index db87084fc1ba..62dc467143ee 100644 --- a/src/rustc/back/link.rs +++ b/src/rustc/back/link.rs @@ -636,7 +636,7 @@ fn link_binary(sess: session, // On linux librt and libdl are an indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically if sess.targ_cfg.os == session::os_linux { - cc_args += ["-lrt", "-ldl"]; + cc_args += ["-lrt", "-ldl", "-lm"]; } if sess.targ_cfg.os == session::os_freebsd { From 9975ad073acc408ee1bb4fe776daeeb175aa8816 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 6 Jun 2012 12:42:56 -0700 Subject: [PATCH 15/53] rustc: Add comments about linking to libm --- src/rustc/back/link.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs index 62dc467143ee..c3e1b4da7727 100644 --- a/src/rustc/back/link.rs +++ b/src/rustc/back/link.rs @@ -636,7 +636,12 @@ fn link_binary(sess: session, // On linux librt and libdl are an indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically if sess.targ_cfg.os == session::os_linux { - cc_args += ["-lrt", "-ldl", "-lm"]; + cc_args += ["-lrt", "-ldl"]; + + // LLVM implements the `frem` instruction as a call to `fmod`, + // which lives in libm. Similar to above, on some linuxes we + // have to be explicit about linking to it. See #2510 + cc_args += ["-lm"]; } if sess.targ_cfg.os == session::os_freebsd { From cba77ffbfa469727314f65405117277839a1783b Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Wed, 6 Jun 2012 14:28:59 -0700 Subject: [PATCH 16/53] syntax: More grammatical error message --- src/libsyntax/diagnostic.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 6d54615e8272..f58333c5599b 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -86,11 +86,14 @@ impl codemap_handler of handler for handler_t { } fn has_errors() -> bool { self.err_count > 0u } fn abort_if_errors() { - if self.err_count > 0u { - let s = #fmt["aborting due to %u previous errors", - self.err_count]; - self.fatal(s); + let s; + alt self.err_count { + 0u { ret; } + 1u { s = "aborting due to previous error"; } + _ { s = #fmt["aborting due to %u previous errors", + self.err_count]; } } + self.fatal(s); } fn warn(msg: str) { self.emit(none, msg, warning); From a6c92f0a179c4f048aaa5145c438611175b41a0d Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 14:19:52 -0700 Subject: [PATCH 17/53] Revert "Revert "Merge pull request #2516 from mozilla/incoming" due to failures" This reverts commit 9fae95860de510f6874810cf43efb83f101246ef. --- src/libcore/cmp.rs | 10 +++++ src/libcore/core.rc | 2 + src/libcore/int-template.rs | 14 +++++++ src/libcore/uint-template.rs | 14 +++++++ src/libstd/sort.rs | 13 ++---- src/rustc/driver/driver.rs | 4 +- src/rustc/driver/rustc.rs | 3 +- src/rustc/metadata/decoder.rs | 2 +- src/rustc/middle/astencode.rs | 9 ---- src/rustc/middle/liveness.rs | 61 ++++------------------------ src/rustc/middle/trans/base.rs | 34 ++-------------- src/rustc/middle/tstate/auxiliary.rs | 5 +-- src/rustc/middle/ty.rs | 6 +-- src/rustc/middle/typeck/astconv.rs | 3 +- src/rustc/middle/typeck/check.rs | 3 +- src/rustc/util/ppaux.rs | 10 ++++- 16 files changed, 79 insertions(+), 114 deletions(-) create mode 100644 src/libcore/cmp.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs new file mode 100644 index 000000000000..aea97cf1649f --- /dev/null +++ b/src/libcore/cmp.rs @@ -0,0 +1,10 @@ +#[doc="Interfaces used for comparison."] + +iface ord { + fn lt(&&other: self) -> bool; +} + +iface eq { + fn eq(&&other: self) -> bool; +} + diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 84cebcceccd8..668eb3c82b9e 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -45,6 +45,7 @@ export tuple; export to_str; export swappable; export dvec, dvec_iter; +export cmp; // NDM seems to be necessary for resolve to work export option_iter; @@ -153,6 +154,7 @@ mod tuple; // Ubiquitous-utility-type modules +mod cmp; mod either; mod iter; mod logging; diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 156724cb0617..4011ac1a18a7 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -1,4 +1,5 @@ import T = inst::T; +import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -10,6 +11,7 @@ export range; export compl; export abs; export parse_buf, from_str, to_str, to_str_bytes, str; +export ord, eq; const min_value: T = -1 as T << (inst::bits - 1 as T); const max_value: T = min_value - 1 as T; @@ -108,6 +110,18 @@ fn to_str_bytes(n: T, radix: uint, f: fn([u8]/&) -> U) -> U { #[doc = "Convert to a string"] fn str(i: T) -> str { ret to_str(i, 10u); } +impl ord of ord for T { + fn lt(&&other: T) -> bool { + ret self < other; + } +} + +impl eq of eq for T { + fn eq(&&other: T) -> bool { + ret self == other; + } +} + // FIXME: Has alignment issues on windows and 32-bit linux #[test] diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index a63d01e6e8e0..7126fb3d007d 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -1,4 +1,5 @@ import T = inst::T; +import cmp::{eq, ord}; export min_value, max_value; export min, max; @@ -10,6 +11,7 @@ export range; export compl; export to_str, to_str_bytes; export from_str, from_str_radix, str, parse_buf; +export ord, eq; const min_value: T = 0 as T; const max_value: T = 0 as T - 1 as T; @@ -49,6 +51,18 @@ pure fn compl(i: T) -> T { max_value ^ i } +impl ord of ord for T { + fn lt(&&other: T) -> bool { + ret self < other; + } +} + +impl eq of eq for T { + fn eq(&&other: T) -> bool { + ret self == other; + } +} + #[doc = " Parse a buffer of bytes diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 7e16578fd9c8..76c71d7ed2aa 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -1,5 +1,6 @@ #[doc = "Sorting methods"]; import vec::len; +import int::{eq, ord}; export le; export merge_sort; @@ -141,7 +142,6 @@ fn qsort3(compare_func_lt: le, compare_func_eq: le, qsort3::(compare_func_lt, compare_func_eq, arr, i, right); } -// FIXME: This should take lt and eq types (#2348) #[doc = " Fancy quicksort. Sorts a mut vector in place. @@ -152,10 +152,9 @@ According to these slides this is the algorithm of choice for This is an unstable sort. "] -fn quick_sort3(compare_func_lt: le, compare_func_eq: le, - arr: [mut T]) { +fn quick_sort3(arr: [mut T]) { if len::(arr) == 0u { ret; } - qsort3::(compare_func_lt, compare_func_eq, arr, 0, + qsort3::({ |x, y| x.lt(y) }, { |x, y| x.eq(y) }, arr, 0, (len::(arr) as int) - 1); } @@ -163,11 +162,7 @@ fn quick_sort3(compare_func_lt: le, compare_func_eq: le, mod test_qsort3 { fn check_sort(v1: [mut int], v2: [mut int]) { let len = vec::len::(v1); - fn lt(&&a: int, &&b: int) -> bool { ret a < b; } - fn equal(&&a: int, &&b: int) -> bool { ret a == b; } - let f1 = lt; - let f2 = equal; - quick_sort3::(f1, f2, v1); + quick_sort3::(v1); let mut i = 0u; while i < len { log(debug, v2[i]); diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 6d4f48595d25..e769455376a5 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -194,7 +194,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, spill_map) = + let last_use_map = time(time_passes, "liveness checking", bind middle::liveness::check_crate(ty_cx, method_map, crate)); time(time_passes, "typestate checking", @@ -216,7 +216,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let maps = {mutbl_map: mutbl_map, root_map: root_map, 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}; + vtable_map: vtable_map}; let (llmod, link_meta) = time(time_passes, "translation", diff --git a/src/rustc/driver/rustc.rs b/src/rustc/driver/rustc.rs index db185215bea5..5e88df1de5ec 100644 --- a/src/rustc/driver/rustc.rs +++ b/src/rustc/driver/rustc.rs @@ -15,7 +15,8 @@ import std::map::hashmap; import getopts::{opt_present}; import rustc::driver::driver::*; import syntax::codemap; -import rustc::driver::{diagnostic, session}; +import syntax::diagnostic; +import rustc::driver::session; import rustc::middle::lint; import io::reader_util; diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 644d519fc0f2..4df45033a77c 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -7,7 +7,6 @@ import syntax::{ast, ast_util}; import syntax::attr; import middle::ty; import syntax::ast_map; -import common::*; import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, parse_ident}; import syntax::print::pprust; @@ -15,6 +14,7 @@ import cmd=cstore::crate_metadata; import util::ppaux::ty_to_str; import ebml::deserializer; import syntax::diagnostic::span_handler; +import common::*; export class_dtor; export get_class_fields; diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 2fd59cb21662..6ebf0ed9ec65 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -57,7 +57,6 @@ type maps = { impl_map: middle::resolve::impl_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, - spill_map: middle::liveness::spill_map }; type decode_ctxt = @{ @@ -839,12 +838,6 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, } } - option::iter(maps.spill_map.find(id)) {|_m| - ebml_w.tag(c::tag_table_spill) {|| - 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); @@ -953,8 +946,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt, dcx.maps.mutbl_map.insert(id, ()); } else if tag == (c::tag_table_copy as uint) { dcx.maps.copy_map.insert(id, ()); - } else if tag == (c::tag_table_spill as uint) { - dcx.maps.spill_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/liveness.rs b/src/rustc/middle/liveness.rs index 3f82e647ab6b..048823f4553f 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -57,7 +57,6 @@ 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 @@ -66,13 +65,6 @@ export spill_map; // list of closed over variables that can be moved into the closure. type last_use_map = hashmap>; -// A set of variable ids which must be spilled (stored on the stack). -// We add in any variables or arguments where: -// (1) the variables are moved; -// (2) the address of the variable/argument is taken; -// or (3) we find a last use (as they may be moved). -type spill_map = hashmap; - enum variable = uint; enum live_node = uint; @@ -85,7 +77,7 @@ enum live_node_kind { fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - crate: @crate) -> (last_use_map, spill_map) { + crate: @crate) -> last_use_map { let visitor = visit::mk_vt(@{ visit_fn: visit_fn, visit_local: visit_local, @@ -94,12 +86,11 @@ fn check_crate(tcx: ty::ctxt, }); let last_use_map = int_hash(); - let spill_map = int_hash(); let initial_maps = @ir_maps(tcx, method_map, - last_use_map, spill_map); + last_use_map); visit::visit_crate(*crate, initial_maps, visitor); tcx.sess.abort_if_errors(); - ret (last_use_map, spill_map); + ret last_use_map; } impl of to_str::to_str for live_node { @@ -162,7 +153,6 @@ class ir_maps { let tcx: ty::ctxt; let method_map: typeck::method_map; let last_use_map: last_use_map; - let spill_map: spill_map; let mut num_live_nodes: uint; let mut num_vars: uint; @@ -174,11 +164,10 @@ class ir_maps { let mut lnks: [live_node_kind]; new(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: last_use_map, spill_map: spill_map) { + last_use_map: last_use_map) { self.tcx = tcx; self.method_map = method_map; self.last_use_map = last_use_map; - self.spill_map = spill_map; self.num_live_nodes = 0u; self.num_vars = 0u; @@ -264,17 +253,6 @@ class ir_maps { self.lnks[*ln] } - 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, ()); - } - vk_arg(*) | vk_field(_) | vk_self | vk_implicit_ret {} - } - } - 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]; @@ -308,7 +286,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, // swap in a new set of IR maps for this function body: let fn_maps = @ir_maps(self.tcx, self.method_map, - self.last_use_map, self.spill_map); + self.last_use_map); #debug["creating fn_maps: %x", ptr::addr_of(*fn_maps) as uint]; @@ -1407,11 +1385,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { vt.visit_expr(f, self, vt); vec::iter2(args, targs) { |arg_expr, arg_ty| alt ty::resolved_mode(self.tcx, arg_ty.mode) { - by_val | by_copy { - vt.visit_expr(arg_expr, self, vt); - } - by_ref | by_mutbl_ref { - self.spill_expr(arg_expr); + by_val | by_copy | by_ref | by_mutbl_ref{ vt.visit_expr(arg_expr, self, vt); } by_move { @@ -1421,10 +1395,6 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { } } - expr_addr_of(_, arg_expr) { - self.spill_expr(arg_expr); - } - // no correctness conditions related to liveness expr_if_check(*) | expr_if(*) | expr_alt(*) | expr_while(*) | expr_loop(*) | @@ -1434,7 +1404,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { expr_assert(*) | expr_check(*) | expr_copy(*) | expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) | expr_ret(*) | expr_break | expr_cont | expr_lit(_) | - expr_block(*) | expr_swap(*) | expr_mac(*) { + expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) { visit::visit_expr(expr, self, vt); } } @@ -1501,10 +1471,7 @@ impl check_methods for @liveness { ln.to_str(), var.to_str()]; alt (*self).live_on_exit(ln, var) { - none { - // update spill map to include this variable, as it is moved: - (*self.ir).add_spill(var); - } + none { } some(lnk) { self.report_illegal_move(span, lnk, var); } @@ -1516,20 +1483,10 @@ impl check_methods for @liveness { some(_) {} none { (*self.ir).add_last_use(expr.id, var); - - // update spill map to include this variable, as it may be moved: - (*self.ir).add_spill(var); } } } - fn spill_expr(expr: @expr) { - alt (*self).variable_from_path(expr) { - some(var) {(*self.ir).add_spill(var)} - none {} - } - } - fn check_move_from_expr(expr: @expr, vt: vt<@liveness>) { #debug["check_move_from_expr(node %d: %s)", expr.id, expr_to_str(expr)]; @@ -1775,4 +1732,4 @@ impl check_methods for @liveness { } } } - } \ No newline at end of file + } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 62c3134e9abd..e6708385b03a 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -3749,6 +3749,8 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block { let ty = expr_ty(bcx, e); let lv = trans_lval(bcx, e); let last_use = (lv.kind == owned && last_use_map.contains_key(e.id)); + #debug["is last use (%s) = %b, %d", expr_to_str(e), last_use, + lv.kind as int]; lval_result_to_dps(lv, ty, last_use, dest) } @@ -4039,29 +4041,10 @@ fn init_local(bcx: block, local: @ast::local) -> block { let ty = node_id_type(bcx, local.node.id); let llptr = alt bcx.fcx.lllocals.find(local.node.id) { some(local_mem(v)) { v } - some(_) { bcx.tcx().sess.span_bug(local.span, + _ { bcx.tcx().sess.span_bug(local.span, "init_local: Someone forgot to document why it's\ safe to assume local.node.init must be local_mem!"); - } - // This is a local that is kept immediate - none { - let initexpr = alt local.node.init { - some({expr, _}) { expr } - none { bcx.tcx().sess.span_bug(local.span, - "init_local: late-initialized var appears to \ - be an immediate -- possibly init_local was called \ - without calling alloc_local"); } - }; - let mut {bcx, val, kind} = trans_temp_lval(bcx, initexpr); - if kind != temporary { - if kind == owned { val = Load(bcx, val); } - let rs = take_ty_immediate(bcx, val, ty); - bcx = rs.bcx; val = rs.val; - add_clean_temp(bcx, val, ty); } - bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val)); - ret bcx; - } }; let mut bcx = bcx; @@ -4341,17 +4324,6 @@ fn alloc_local(cx: block, local: @ast::local) -> block { ast::pat_ident(pth, none) { some(path_to_ident(pth)) } _ { none } }; - // Do not allocate space for locals that can be kept immediate. - let ccx = cx.ccx(); - if option::is_some(simple_name) && - !ccx.maps.mutbl_map.contains_key(local.node.pat.id) && - !ccx.maps.spill_map.contains_key(local.node.pat.id) && - ty::type_is_immediate(t) { - alt local.node.init { - some({op: ast::init_assign, _}) { ret cx; } - _ {} - } - } let val = alloc_ty(cx, t); if cx.sess().opts.debuginfo { option::iter(simple_name) {|name| diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index c34953ac33e6..a41812f72a79 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -13,9 +13,8 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, set_postcondition, ts_ann, clear_in_postcond, clear_in_poststate_}; -import tritv::*; -import bitvectors::promises_; import driver::session::session; +import tritv::{dont_care, tfalse, tritv_get, ttrue}; import syntax::print::pprust::{constr_args_to_str, lit_to_str}; @@ -811,7 +810,7 @@ fn copy_in_poststate_two(fcx: fn_ctxt, src_post: poststate, // dest def_id let insts = find_instances(fcx, subst, val); for insts.each {|p| - if promises_(p.from, src_post) { + if bitvectors::promises_(p.from, src_post) { set_in_poststate_(p.to, target_post); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 3b32bca1e5f8..73f601cf4b06 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -4,19 +4,19 @@ import std::map::hashmap; import driver::session; import session::session; import syntax::{ast, ast_map}; -import syntax::ast::*; import syntax::ast_util; import syntax::ast_util::{is_local, local_def, split_class_items, new_def_hash}; import syntax::codemap::span; import metadata::csearch; -import util::common::*; import util::ppaux::region_to_str; import util::ppaux::vstore_to_str; import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str}; -import syntax::print::pprust::*; import middle::lint::{get_warning_level, vecs_not_implicitly_copyable, ignore}; +import syntax::ast::*; +import syntax::print::pprust::*; + export ty_vid, region_vid, vid; export br_hashmap; export is_instantiable; diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index d8ce3d83a603..476ef9d3ba55 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -45,7 +45,8 @@ an rptr (`&r.T`) use the region `r` that appears in the rptr. "]; import check::fn_ctxt; -import rscope::*; +import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; +import rscope::{in_binding_rscope, region_scope, type_rscope}; iface ast_conv { fn tcx() -> ty::ctxt; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 2649dc6c6756..70167192afc8 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -71,7 +71,8 @@ import collect::{methods}; // ccx.to_ty() import method::{methods}; // methods for method::lookup import middle::ty::tys_in_fn_ty; import regionmanip::{replace_bound_regions_in_fn_ty, region_of}; -import rscope::*; +import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; +import rscope::{in_binding_rscope, region_scope, type_rscope}; type fn_ctxt = // var_bindings, locals and next_var_id are shared diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 60f4ea8dabff..c5c445702d51 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -1,6 +1,14 @@ import std::map::hashmap; import middle::ty; -import middle::ty::*; +import middle::ty::{arg, bound_region, br_anon, br_named, canon_mode}; +import middle::ty::{ck_block, ck_box, ck_uniq, constr, ctxt, field, method}; +import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t}; +import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_constr, ty_enum}; +import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_iface, ty_int}; +import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; +import middle::ty::{ty_ptr, ty_rec, ty_res, ty_rptr, ty_self, ty_str, ty_tup}; +import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral}; +import middle::ty::{ty_vec, vid}; import metadata::encoder; import syntax::codemap; import syntax::print::pprust; From 5e8ef74e22eaf49518cd93838ec8b2843bc916a9 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 14:20:31 -0700 Subject: [PATCH 18/53] Revert "Revert "Forbid classes with no fields" due to test failures" This reverts commit e56a6e8cb0ca2be26bb71918447459865803a630. --- src/rustc/middle/typeck/check.rs | 6 ++++++ src/test/compile-fail/issue-2509-a.rs | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/compile-fail/issue-2509-a.rs diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 70167192afc8..b3f7c5a93885 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -387,6 +387,12 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { }; // typecheck the members for members.each {|m| check_class_member(class_ccx, class_t, m); } + // Check that there's at least one field + let (fields,_) = split_class_items(members); + if fields.len() < 1u { + ccx.tcx.sess.span_err(it.span, "A class must have at least one \ + field"); + } // Check that the class is instantiable check_instantiable(ccx.tcx, it.span, it.id); } diff --git a/src/test/compile-fail/issue-2509-a.rs b/src/test/compile-fail/issue-2509-a.rs new file mode 100644 index 000000000000..a500d249c07a --- /dev/null +++ b/src/test/compile-fail/issue-2509-a.rs @@ -0,0 +1,9 @@ +class c { //! ERROR A class must have at least one field + new() { } +} + +fn main() { + let a = c(); + let x = [a]; + let _y = x[0]; +} From feece9814af5ed64ecf1961e4fff9b681f3b45ac Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 14:37:41 -0700 Subject: [PATCH 19/53] Revert "Revert "Fix test case so the class in it is non-empty" due to test failures" This reverts commit c6e16c5668a86245259a4f542a62199b2023b89b. --- src/test/run-pass/conditional-compile.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 8f4bd22f75dd..2b64840d8301 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -26,11 +26,13 @@ enum tg { bar, } #[cfg(bogus)] class r { - new(i:int) {} + let i: int; + new(i:int) { self.i = i; } } class r { - new(i:int) {} + let i: int; + new(i:int) { self.i = i; } } #[cfg(bogus)] From a5c9e8d59ed49725550ebd9e60871d51736393b4 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 14:58:41 -0700 Subject: [PATCH 20/53] Fix tests to avoid empty classes --- src/test/compile-fail/noncopyable-class.rs | 5 +++-- src/test/compile-fail/regions-bounds.rs | 2 +- src/test/compile-fail/vec-res-add.rs | 3 ++- src/test/run-fail/morestack2.rs | 5 +++-- src/test/run-fail/morestack3.rs | 5 +++-- src/test/run-fail/morestack4.rs | 5 +++-- src/test/run-fail/rt-set-exit-status-fail2.rs | 5 +++-- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/test/compile-fail/noncopyable-class.rs b/src/test/compile-fail/noncopyable-class.rs index da0a0a488f50..736fee0f66cb 100644 --- a/src/test/compile-fail/noncopyable-class.rs +++ b/src/test/compile-fail/noncopyable-class.rs @@ -3,14 +3,15 @@ // Test that a class with a non-copyable field can't be // copied class bar { - new() {} + let x: int; + new(x:int) {self.x = x;} drop {} } class foo { let i: int; let j: bar; - new(i:int) { self.i = i; self.j = bar(); } + new(i:int) { self.i = i; self.j = bar(5); } } fn main() { let x <- foo(10); let y = x; log(error, x); } diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 1582c8a049fc..c62db9b8fff2 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -4,7 +4,7 @@ enum an_enum/& { } iface an_iface/& { } -class a_class/& { new() { } } +class a_class/& { let x:int; new(x:int) { self.x = x; } } fn a_fn1(e: an_enum/&a) -> an_enum/&b { ret e; //! ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a` diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index ea411ca27a2f..f6388b197983 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -1,7 +1,8 @@ // error-pattern: copying a noncopyable value class r { - new(_i:int) {} + let i:int; + new(i:int) {self.i = i;} drop {} } diff --git a/src/test/run-fail/morestack2.rs b/src/test/run-fail/morestack2.rs index 736d0d81a5dd..d68e9c497895 100644 --- a/src/test/run-fail/morestack2.rs +++ b/src/test/run-fail/morestack2.rs @@ -21,7 +21,8 @@ fn getbig_call_c_and_fail(i: int) { } class and_then_get_big_again { - new() {} + let x:int; + new(x:int) {self.x = x;} drop { fn getbig(i: int) { if i != 0 { @@ -34,7 +35,7 @@ class and_then_get_big_again { fn main() { task::spawn {|| - let r = and_then_get_big_again(); + let r = and_then_get_big_again(4); getbig_call_c_and_fail(10000); }; } \ No newline at end of file diff --git a/src/test/run-fail/morestack3.rs b/src/test/run-fail/morestack3.rs index 61b0b824d25a..0f0aea5ccd12 100644 --- a/src/test/run-fail/morestack3.rs +++ b/src/test/run-fail/morestack3.rs @@ -5,7 +5,7 @@ use std; fn getbig_and_fail(&&i: int) { - let _r = and_then_get_big_again(); + let _r = and_then_get_big_again(5); if i != 0 { getbig_and_fail(i - 1); } else { @@ -14,7 +14,8 @@ fn getbig_and_fail(&&i: int) { } class and_then_get_big_again { - new() {} + let x:int; + new(x:int) {self.x = x;} drop { fn getbig(i: int) { if i != 0 { diff --git a/src/test/run-fail/morestack4.rs b/src/test/run-fail/morestack4.rs index 63155b50de15..b1c86d5110a9 100644 --- a/src/test/run-fail/morestack4.rs +++ b/src/test/run-fail/morestack4.rs @@ -5,7 +5,7 @@ use std; fn getbig_and_fail(&&i: int) { - let r = and_then_get_big_again(); + let r = and_then_get_big_again(5); if i != 0 { getbig_and_fail(i - 1); } else { @@ -14,7 +14,8 @@ fn getbig_and_fail(&&i: int) { } class and_then_get_big_again { - new() {} + let x:int; + new(x:int) {self.x = x;} drop {} } diff --git a/src/test/run-fail/rt-set-exit-status-fail2.rs b/src/test/run-fail/rt-set-exit-status-fail2.rs index 680df73d62e4..2c2665446cdf 100644 --- a/src/test/run-fail/rt-set-exit-status-fail2.rs +++ b/src/test/run-fail/rt-set-exit-status-fail2.rs @@ -1,19 +1,20 @@ // error-pattern:whatever class r { + let x:int; // Setting the exit status after the runtime has already // failed has no effect and the process exits with the // runtime's exit code drop { os::set_exit_status(50); } - new() {} + new(x:int) {self.x = x;} } fn main() { log(error, "whatever"); task::spawn {|| - let i = r(); + let i = r(5); }; fail; } \ No newline at end of file From 32e448e0da9fd1e93c5bcce953d1ffbc4193565a Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 5 Jun 2012 16:20:12 -0700 Subject: [PATCH 21/53] Change subtypes_require to handle class fields correctly --- src/rustc/middle/ty.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 73f601cf4b06..a426ded68f85 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -1678,11 +1678,8 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool { ty_class(did, substs) { vec::push(*seen, did); - let r = vec::any(lookup_class_fields(cx, did)) {|f| - let fty = ty::lookup_item_type(cx, f.id); - let sty = subst(cx, substs, fty.ty); - type_requires(cx, seen, r_ty, sty) - }; + let r = vec::any(class_items_as_fields(cx, did, substs)) {|f| + type_requires(cx, seen, r_ty, f.mt.ty)}; vec::pop(*seen); r } From be83a12ff7bcc9c620bab8297654f6e006b50d6d Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Jun 2012 16:01:12 -0700 Subject: [PATCH 22/53] Add some testcases for bug #2470. --- .../bug-2470-bounds-check-overflow-2.rs | 17 +++++++++++ .../bug-2470-bounds-check-overflow-3.rs | 28 +++++++++++++++++++ .../bug-2470-bounds-check-overflow.rs | 24 ++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow-2.rs create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow-3.rs create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow.rs diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs b/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs new file mode 100644 index 000000000000..215fd53ce5ed --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs @@ -0,0 +1,17 @@ +// xfail-test +// error-pattern:bounds check + +fn main() { + let x = [1u,2u,3u]; + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by comparing a scaled index value to the vector's + // length (in bytes), because the scaling of the index will cause it to + // wrap around to a small number. + + let idx = uint::max_value & !(uint::max_value >> 1u); + #error("ov2 idx = 0x%x", idx); + + // This should fail. + #error("ov2 0x%x", x[idx]); +} \ No newline at end of file diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs b/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs new file mode 100644 index 000000000000..26737f8a9fab --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs @@ -0,0 +1,28 @@ +// xfail-test +// error-pattern:bounds check + +#[cfg(target_arch="x86")] +fn main() { + let x = [1u,2u,3u]; + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by truncating the index value to the size of the + // machine word, losing relevant bits of the index value. + + // This test is only meaningful on 32-bit hosts. + + let idx = u64::max_value & !(u64::max_value >> 1u); + #error("ov3 idx = 0x%8.8x%8.8x", + (idx >> 32) as uint, + idx as uint); + + // This should fail. + #error("ov3 0x%x", x[idx]); +} + +#[cfg(target_arch="x86_64")] +fn main() { + // This version just fails anyways, for symmetry on 64-bit hosts. + let x = [1u,2u,3u]; + #error("ov3 0x%x", x[200]); +} diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow.rs b/src/test/run-fail/bug-2470-bounds-check-overflow.rs new file mode 100644 index 000000000000..84bd9ab5c76e --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow.rs @@ -0,0 +1,24 @@ +// error-pattern:bounds check + +fn main() { + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by comparing the scaled index to the vector's + // address-bounds, since we've scaled the index to wrap around to the + // address of the 0th cell in the array (even though the index is + // huge). + + let x = [1u,2u,3u]; + vec::unpack_slice(x) {|p, _len| + let base = p as uint; // base = 0x1230 say + let idx = base / sys::size_of::(); // idx = 0x0246 say + #error("ov1 base = 0x%x", base); + #error("ov1 idx = 0x%x", idx); + #error("ov1 sizeof::() = 0x%x", sys::size_of::()); + #error("ov1 idx * sizeof::() = 0x%x", + idx * sys::size_of::()); + + // This should fail. + #error("ov1 0x%x", x[idx]); + } +} \ No newline at end of file From ef32ffd0b1602ff87536508a7f75fd9b1510b4e9 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 5 Jun 2012 14:44:13 -0700 Subject: [PATCH 23/53] core: Remove swappable. Unused --- src/libcore/core.rc | 2 - src/libcore/swappable.rs | 98 ----------------------------- src/test/run-pass/swappable-test.rs | 13 ---- 3 files changed, 113 deletions(-) delete mode 100644 src/libcore/swappable.rs delete mode 100644 src/test/run-pass/swappable-test.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 84cebcceccd8..6b4c7ad7d3ca 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -43,7 +43,6 @@ export comm, task, future; export extfmt; export tuple; export to_str; -export swappable; export dvec, dvec_iter; // NDM seems to be necessary for resolve to work @@ -164,7 +163,6 @@ mod option_iter { } mod result; mod to_str; -mod swappable; mod dvec; #[path="iter-trait"] mod dvec_iter { diff --git a/src/libcore/swappable.rs b/src/libcore/swappable.rs deleted file mode 100644 index 5df9b2c48463..000000000000 --- a/src/libcore/swappable.rs +++ /dev/null @@ -1,98 +0,0 @@ -export swappable; -export unwrap; -export methods; - -#[doc = " -A value that may be swapped out temporarily while it is being processed -and then replaced. Swappables are most useful when working with unique -values, which often cannot be mutated unless they are stored in the local -stack frame to ensure memory safety. - -The type guarantees the invariant that the value is always \"swapped in\" -except during the execution of the `swap()` and `with()` methods. -"] -type swappable = { - mut o_t: option -}; - -#[doc = "Create a swappable swapped in with a given initial value"] -fn swappable(+t: A) -> swappable { - {mut o_t: some(t)} -} - -#[doc = "Consumes a swappable and returns its contents without copying"] -fn unwrap(-s: swappable) -> A { - let {o_t: o_t} <- s; - option::unwrap(o_t) -} - -impl methods for swappable { - #[doc = " - Overwrites the contents of the swappable - "] - fn set(+a: A) { - self.o_t <- some(a); - } - - #[doc = " - Invokes `f()` with the current value but replaces the - current value when complete. Returns the result of `f()`. - - Attempts to read or access the receiver while `f()` is executing - will fail dynamically. - "] - fn with(f: fn(A) -> B) -> B { - let mut o_u = none; - self.swap { |t| o_u <- some(f(t)); t } - option::unwrap(o_u) - } - - #[doc = " - Invokes `f()` with the current value and then replaces the - current value with the result of `f()`. - - Attempts to read or access the receiver while `f()` is executing - will fail dynamically. - "] - fn swap(f: fn(-A) -> A) { - alt self.o_t { - none { fail "no value present---already swapped?"; } - some(_) {} - } - - let mut o_t = none; - o_t <-> self.o_t; - self.o_t <- some(f(option::unwrap(o_t))); - } - - #[doc = "True if there is a value present in this swappable"] - fn is_present() -> bool { - alt self.o_t { - none {false} - some(_) {true} - } - } - - #[doc = " - Removes the value from the swappable. Any further attempts - to use the swapabble without first invoking `set()` will fail. - "] - fn take() -> A { - alt self.o_t { - none { fail "swapped out"; } - some(_) {} - } - - let mut o_t = none; - option::unwrap(o_t) - } -} - -impl methods for swappable { - #[doc = " - Copies out the contents of the swappable - "] - fn get() -> A { - self.o_t.get() - } -} \ No newline at end of file diff --git a/src/test/run-pass/swappable-test.rs b/src/test/run-pass/swappable-test.rs deleted file mode 100644 index ee3446489017..000000000000 --- a/src/test/run-pass/swappable-test.rs +++ /dev/null @@ -1,13 +0,0 @@ -import swappable::{swappable, methods}; - -fn main() { - let d = swappable(3); - assert d.get() == 3; - d.set(4); - assert d.get() == 4; - d.swap { |i| i + 1 }; - assert d.get() == 5; - assert d.with { |i| i + 1 } == 6; - assert d.get() == 5; - assert swappable::unwrap(d) == 5; -} \ No newline at end of file From 107442d99496dbb037bc965d94904f21740f726f Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Jun 2012 16:01:12 -0700 Subject: [PATCH 24/53] Add some testcases for bug #2470. --- .../bug-2470-bounds-check-overflow-2.rs | 17 +++++++++++ .../bug-2470-bounds-check-overflow-3.rs | 28 +++++++++++++++++++ .../bug-2470-bounds-check-overflow.rs | 24 ++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow-2.rs create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow-3.rs create mode 100644 src/test/run-fail/bug-2470-bounds-check-overflow.rs diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs b/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs new file mode 100644 index 000000000000..215fd53ce5ed --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow-2.rs @@ -0,0 +1,17 @@ +// xfail-test +// error-pattern:bounds check + +fn main() { + let x = [1u,2u,3u]; + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by comparing a scaled index value to the vector's + // length (in bytes), because the scaling of the index will cause it to + // wrap around to a small number. + + let idx = uint::max_value & !(uint::max_value >> 1u); + #error("ov2 idx = 0x%x", idx); + + // This should fail. + #error("ov2 0x%x", x[idx]); +} \ No newline at end of file diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs b/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs new file mode 100644 index 000000000000..26737f8a9fab --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow-3.rs @@ -0,0 +1,28 @@ +// xfail-test +// error-pattern:bounds check + +#[cfg(target_arch="x86")] +fn main() { + let x = [1u,2u,3u]; + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by truncating the index value to the size of the + // machine word, losing relevant bits of the index value. + + // This test is only meaningful on 32-bit hosts. + + let idx = u64::max_value & !(u64::max_value >> 1u); + #error("ov3 idx = 0x%8.8x%8.8x", + (idx >> 32) as uint, + idx as uint); + + // This should fail. + #error("ov3 0x%x", x[idx]); +} + +#[cfg(target_arch="x86_64")] +fn main() { + // This version just fails anyways, for symmetry on 64-bit hosts. + let x = [1u,2u,3u]; + #error("ov3 0x%x", x[200]); +} diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow.rs b/src/test/run-fail/bug-2470-bounds-check-overflow.rs new file mode 100644 index 000000000000..84bd9ab5c76e --- /dev/null +++ b/src/test/run-fail/bug-2470-bounds-check-overflow.rs @@ -0,0 +1,24 @@ +// error-pattern:bounds check + +fn main() { + + // This should cause a bounds-check failure, but may not if we do our + // bounds checking by comparing the scaled index to the vector's + // address-bounds, since we've scaled the index to wrap around to the + // address of the 0th cell in the array (even though the index is + // huge). + + let x = [1u,2u,3u]; + vec::unpack_slice(x) {|p, _len| + let base = p as uint; // base = 0x1230 say + let idx = base / sys::size_of::(); // idx = 0x0246 say + #error("ov1 base = 0x%x", base); + #error("ov1 idx = 0x%x", idx); + #error("ov1 sizeof::() = 0x%x", sys::size_of::()); + #error("ov1 idx * sizeof::() = 0x%x", + idx * sys::size_of::()); + + // This should fail. + #error("ov1 0x%x", x[idx]); + } +} \ No newline at end of file From d542e67827e0ad1a3df5fd248d9c09997b5dcbba Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Wed, 6 Jun 2012 18:22:49 -0700 Subject: [PATCH 25/53] Do some cleanup of the allocation code. --- src/rustc/middle/trans/base.rs | 90 ++++++++++++++----------------- src/rustc/middle/trans/closure.rs | 5 +- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index e6708385b03a..ff297c5dcd48 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -62,6 +62,12 @@ enum dest { ignore, } +// Heap selectors. Indicate which heap something should go on. +enum heap { + heap_shared, + heap_exchange, +} + fn dest_str(ccx: @crate_ctxt, d: dest) -> str { alt d { by_val(v) { #fmt["by_val(%s)", val_str(ccx.tn, *v)] } @@ -341,75 +347,61 @@ fn opaque_box_body(bcx: block, PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t))) } -// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to +// malloc_raw: expects an unboxed type and returns a pointer to // enough space for a box of that type. This includes a rust_opaque_box // header. -fn malloc_boxed_raw(bcx: block, t: ty::t, - &static_ti: option<@tydesc_info>) -> ValueRef { - let _icx = bcx.insn_ctxt("trans_malloc_boxed_raw"); +fn malloc_raw(bcx: block, t: ty::t, heap: heap) -> ValueRef { + let _icx = bcx.insn_ctxt("malloc_raw"); let ccx = bcx.ccx(); - // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc - // wants. - let box_ptr = ty::mk_imm_box(ccx.tcx, t); - let llty = type_of(ccx, box_ptr); + let (mk_fn, upcall) = alt heap { + heap_shared { (ty::mk_imm_box, ccx.upcalls.malloc) } + heap_exchange { + (ty::mk_imm_uniq, ccx.upcalls.exchange_malloc ) + } + }; - // Get the tydesc for the body: - let lltydesc = get_tydesc(ccx, t, static_ti); - lazily_emit_all_tydesc_glue(ccx, copy static_ti); - - // Allocate space: - let rval = Call(bcx, ccx.upcalls.malloc, [lltydesc]); - ret PointerCast(bcx, rval, llty); -} - -// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box, -// initializes the reference count to 1, and pulls out the body and rc -fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} { - let _icx = bcx.insn_ctxt("trans_malloc_boxed"); - let mut ti = none; - let box = malloc_boxed_raw(bcx, t, ti); - let box_no_addrspace = non_gc_box_cast( - bcx, box, ty::mk_imm_box(bcx.tcx(), t)); - let body = GEPi(bcx, box_no_addrspace, [0u, abi::box_field_body]); - ret {box: box, body: body}; -} - -fn malloc_unique_raw(bcx: block, t: ty::t) -> ValueRef { - let _icx = bcx.insn_ctxt("malloc_unique_box_raw"); - let ccx = bcx.ccx(); - - // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc - // wants. - let box_ptr = ty::mk_imm_uniq(ccx.tcx, t); - let llty = type_of(ccx, box_ptr); + // Grab the TypeRef type of box_ptr_ty. + let box_ptr_ty = mk_fn(bcx.tcx(), t); + let llty = type_of(ccx, box_ptr_ty); // Get the tydesc for the body: let mut static_ti = none; let lltydesc = get_tydesc(ccx, t, static_ti); - lazily_emit_all_tydesc_glue(ccx, static_ti); + lazily_emit_all_tydesc_glue(ccx, copy static_ti); // Allocate space: - let rval = Call(bcx, ccx.upcalls.exchange_malloc, [lltydesc]); + let rval = Call(bcx, upcall, [lltydesc]); ret PointerCast(bcx, rval, llty); } -fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} { - let _icx = bcx.insn_ctxt("malloc_unique_box"); - let box = malloc_unique_raw(bcx, t); - let non_gc_box = non_gc_box_cast(bcx, box, ty::mk_imm_uniq(bcx.tcx(), t)); +// malloc_general: usefully wraps malloc_raw; allocates a box, +// and pulls out the body +fn malloc_general(bcx: block, t: ty::t, heap: heap) -> + {box: ValueRef, body: ValueRef} { + let _icx = bcx.insn_ctxt("malloc_general"); + let mk_ty = alt heap { heap_shared { ty::mk_imm_box } + heap_exchange { ty::mk_imm_uniq } }; + let box = malloc_raw(bcx, t, heap); + let non_gc_box = non_gc_box_cast(bcx, box, mk_ty(bcx.tcx(), t)); let body = GEPi(bcx, non_gc_box, [0u, abi::box_field_body]); ret {box: box, body: body}; } +fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} { + malloc_general(bcx, t, heap_shared) +} +fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} { + malloc_general(bcx, t, heap_exchange) +} + fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("malloc_unique_box_raw"); + let _icx = bcx.insn_ctxt("malloc_unique_dyn_raw"); let ccx = bcx.ccx(); - // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc - // wants. - let box_ptr = ty::mk_imm_uniq(ccx.tcx, t); - let llty = type_of(ccx, box_ptr); + // Grab the TypeRef type of box_ptr_ty. + let box_ptr_ty = ty::mk_imm_uniq(ccx.tcx, t); + let llty = type_of(ccx, box_ptr_ty); // Get the tydesc for the body: let mut static_ti = none; @@ -423,7 +415,7 @@ fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef { fn malloc_unique_dyn(bcx: block, t: ty::t, size: ValueRef ) -> {box: ValueRef, body: ValueRef} { - let _icx = bcx.insn_ctxt("malloc_unique_box"); + let _icx = bcx.insn_ctxt("malloc_unique_dyn"); let box = malloc_unique_dyn_raw(bcx, t, size); let body = GEPi(bcx, box, [0u, abi::box_field_body]); ret {box: box, body: body}; diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs index 9057c9ef6302..88cd126b1e4d 100644 --- a/src/rustc/middle/trans/closure.rs +++ b/src/rustc/middle/trans/closure.rs @@ -175,11 +175,12 @@ fn allocate_cbox(bcx: block, let mut temp_cleanups = []; let (bcx, box) = alt ck { ty::ck_box { - let box = malloc_boxed_raw(bcx, cdata_ty, ti); + get_tydesc(ccx, cdata_ty, ti); + let box = malloc_raw(bcx, cdata_ty, heap_shared); (bcx, box) } ty::ck_uniq { - let box = malloc_unique_raw(bcx, cdata_ty); + let box = malloc_raw(bcx, cdata_ty, heap_exchange); (bcx, box) } ty::ck_block { From bede54b14acb093e86a936d5ba62ff2af8b558d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 2 Jun 2012 20:48:53 -0700 Subject: [PATCH 26/53] misc. copies in core/syntax to please borrowck --- src/libcore/future.rs | 2 +- src/libcore/io.rs | 2 +- src/libsyntax/ext/qquote.rs | 2 +- src/libsyntax/parse/token.rs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/future.rs b/src/libcore/future.rs index e0321b452878..6152b83536a8 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future.rs @@ -108,7 +108,7 @@ fn get(future: future) -> A { fn with(future: future, blk: fn(A) -> B) -> B { #[doc = "Work with the value without copying it"]; - let v = alt future.v { + let v = alt copy future.v { either::left(v) { v } either::right(f) { let v = @f(); diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 02371ea7625d..b18be417019b 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -613,7 +613,7 @@ impl of writer for mem_buffer { // FIXME #2004--use memcpy here? let mut pos = self.pos, vpos = 0u; while vpos < vlen && pos < buf_len { - self.buf.set_elt(pos, v[vpos]); + self.buf.set_elt(pos, copy v[vpos]); pos += 1u; vpos += 1u; } diff --git a/src/libsyntax/ext/qquote.rs b/src/libsyntax/ext/qquote.rs index f3c7de97865a..1a7ae69e79df 100644 --- a/src/libsyntax/ext/qquote.rs +++ b/src/libsyntax/ext/qquote.rs @@ -212,7 +212,7 @@ fn finish state = skip(str::char_len(repl)); str2 += repl; } - alt state { + alt copy state { active {str::push_char(str2, ch);} skip(1u) {state = blank;} skip(sk) {state = skip (sk-1u);} diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index cb92aad04c70..bbbd09632ef8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -184,16 +184,16 @@ fn is_lit(t: token::token) -> bool { } } -fn is_ident(t: token::token) -> bool { +pure fn is_ident(t: token::token) -> bool { alt t { token::IDENT(_, _) { ret true; } _ { } } ret false; } -fn is_plain_ident(t: token::token) -> bool { +pure fn is_plain_ident(t: token::token) -> bool { ret alt t { token::IDENT(_, false) { true } _ { false } }; } -fn is_bar(t: token::token) -> bool { +pure fn is_bar(t: token::token) -> bool { alt t { token::BINOP(token::OR) | token::OROR { true } _ { false } } } From 60913bf04590e0cb6d80290b0e15b00046dfaeaa Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 2 Jun 2012 20:49:05 -0700 Subject: [PATCH 27/53] constrain scope of mut ptr to please borrowck --- src/libstd/arc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 063fdd9b9a49..3445d7399afa 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -24,9 +24,7 @@ type arc_data = { resource arc_destruct(data: *libc::c_void) { unsafe { let data: ~arc_data = unsafe::reinterpret_cast(data); - let ref_ptr = &mut data.count; - - let new_count = rustrt::rust_atomic_decrement(ref_ptr); + let new_count = rustrt::rust_atomic_decrement(&mut data.count); assert new_count >= 0; if new_count == 0 { // drop glue takes over. From 83d290f461c8cf3fe65e682162f3acd4a6369478 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 2 Jun 2012 20:49:39 -0700 Subject: [PATCH 28/53] add misc. pure modifiers in core --- src/libcore/sys.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 93f204cb58f5..e0fd21f6c4a1 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -17,9 +17,9 @@ enum type_desc = { #[abi = "cdecl"] native mod rustrt { - fn refcount(t: *()) -> libc::intptr_t; + pure fn refcount(t: *()) -> libc::intptr_t; fn unsupervise(); - fn shape_log_str(t: *sys::type_desc, data: *()) -> str; + pure fn shape_log_str(t: *sys::type_desc, data: *()) -> str; } #[abi = "rust-intrinsic"] @@ -36,13 +36,13 @@ Returns a pointer to a type descriptor. Useful for calling certain function in the Rust runtime or otherwise performing dark magick. "] -fn get_type_desc() -> *type_desc { - rusti::get_tydesc::() as *type_desc +pure fn get_type_desc() -> *type_desc { + unchecked { rusti::get_tydesc::() as *type_desc } } #[doc = "Returns the size of a type"] -fn size_of() -> uint unsafe { - rusti::size_of::() +pure fn size_of() -> uint unsafe { + unchecked { rusti::size_of::() } } #[doc = " @@ -51,23 +51,23 @@ Returns the ABI-required minimum alignment of a type This is the alignment used for struct fields. It may be smaller than the preferred alignment. "] -fn min_align_of() -> uint unsafe { - rusti::min_align_of::() +pure fn min_align_of() -> uint unsafe { + unchecked { rusti::min_align_of::() } } #[doc = "Returns the preferred alignment of a type"] -fn pref_align_of() -> uint unsafe { - rusti::pref_align_of::() +pure fn pref_align_of() -> uint unsafe { + unchecked { rusti::pref_align_of::() } } #[doc = "Returns the refcount of a shared box"] -fn refcount(t: @T) -> uint { +pure fn refcount(t: @T) -> uint { unsafe { ret rustrt::refcount(unsafe::reinterpret_cast(t)) as uint; } } -fn log_str(t: T) -> str { +pure fn log_str(t: T) -> str { unsafe { let data_ptr: *() = unsafe::reinterpret_cast(ptr::addr_of(t)); rustrt::shape_log_str(get_type_desc::(), data_ptr) From b61071d953019ccfcc8b5c53f737256a1c64230d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 2 Jun 2012 20:50:21 -0700 Subject: [PATCH 29/53] make lookup fn pure in codemap --- src/libsyntax/codemap.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 259041959d4c..0fa419cd4a96 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -77,7 +77,7 @@ fn next_line(file: filemap, chpos: uint, byte_pos: uint) { file.lines += [{ch: chpos, byte: byte_pos + file.start_pos.byte}]; } -type lookup_fn = fn@(file_pos) -> uint; +type lookup_fn = pure fn(file_pos) -> uint; fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn) -> {fm: filemap, line: uint} @@ -108,12 +108,12 @@ fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc { } fn lookup_char_pos(map: codemap, pos: uint) -> loc { - fn lookup(pos: file_pos) -> uint { ret pos.ch; } + pure fn lookup(pos: file_pos) -> uint { ret pos.ch; } ret lookup_pos(map, pos, lookup); } fn lookup_byte_pos(map: codemap, pos: uint) -> loc { - fn lookup(pos: file_pos) -> uint { ret pos.byte; } + pure fn lookup(pos: file_pos) -> uint { ret pos.byte; } ret lookup_pos(map, pos, lookup); } @@ -139,7 +139,7 @@ fn lookup_char_pos_adj(map: codemap, pos: uint) } fn adjust_span(map: codemap, sp: span) -> span { - fn lookup(pos: file_pos) -> uint { ret pos.ch; } + pure fn lookup(pos: file_pos) -> uint { ret pos.ch; } let line = lookup_line(map, sp.lo, lookup); alt (line.fm.substr) { fss_none {sp} @@ -198,7 +198,8 @@ fn get_line(fm: filemap, line: int) -> str unsafe { fn lookup_byte_offset(cm: codemap::codemap, chpos: uint) -> {fm: filemap, pos: uint} { - let {fm, line} = lookup_line(cm, chpos, {|pos| pos.ch}); + pure fn lookup(pos: file_pos) -> uint { ret pos.ch; } + let {fm, line} = lookup_line(cm, chpos, lookup); let line_offset = fm.lines[line].byte - fm.start_pos.byte; let col = chpos - fm.lines[line].ch; let col_offset = str::count_bytes(*fm.src, line_offset, col); From 64c78971876df254d346c237fa7173770610c066 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 2 Jun 2012 21:07:53 -0700 Subject: [PATCH 30/53] exempt unsafe ptrs from by-val checks --- src/rustc/middle/borrowck/gather_loans.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index 1b18ff3f94b1..df16a50f8ff0 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -86,8 +86,10 @@ fn req_loans_in_expr(ex: @ast::expr, // passing the buck onto us to enforce this) alt opt_deref_kind(arg_ty.ty) { - some(deref_ptr(region_ptr)) { + some(deref_ptr(region_ptr)) | + some(deref_ptr(unsafe_ptr)) { /* region pointers are (by induction) guaranteed */ + /* unsafe pointers are the user's problem */ } none { /* not a pointer, no worries */ From 3bc42d5661d7e41885ef192bc2f4a5b8410a79f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Jun 2012 07:34:10 -0700 Subject: [PATCH 31/53] distinguish by-val passes of pointer and non-pointer things --- src/rustc/middle/borrowck/gather_loans.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index df16a50f8ff0..373488e55470 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -84,6 +84,12 @@ fn req_loans_in_expr(ex: @ast::expr, // the pointer to be borrowed as immutable even if it // is mutable in the caller's frame, thus effectively // passing the buck onto us to enforce this) + // + // FIXME---this handling is not really adequate. For + // example, if there is a type like, {f: [int]}, we + // will ignore it, but we ought to be requiring it to + // be immutable (whereas something like {f:int} would + // be fine). alt opt_deref_kind(arg_ty.ty) { some(deref_ptr(region_ptr)) | @@ -91,10 +97,11 @@ fn req_loans_in_expr(ex: @ast::expr, /* region pointers are (by induction) guaranteed */ /* unsafe pointers are the user's problem */ } + some(deref_comp(_)) | none { /* not a pointer, no worries */ } - some(_) { + some(deref_ptr(_)) { let arg_cmt = self.bccx.cat_borrow_of_expr(arg); self.guarantee_valid(arg_cmt, m_const, scope_r); } From b828df93f666494a9d79b91264a4ef953688d001 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Jun 2012 07:34:52 -0700 Subject: [PATCH 32/53] miscellaneous pure annotations and other small changes. it seems that, to be truly useful, pure fns really need the ability to modify their parameters. alternatively, we could rewrite the functions that modify their arguments to take/return. --- src/libcore/rand.rs | 2 +- src/libcore/str.rs | 215 ++++++++++++++++++++++++-------------------- src/libcore/vec.rs | 6 +- 3 files changed, 122 insertions(+), 101 deletions(-) diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 26cf00bbcd10..71bd1025d1db 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -218,7 +218,7 @@ impl extensions for rng { } #[doc = "Shuffle a mutable vec in place"] - fn shuffle_mut(&values: [mut T]) { + fn shuffle_mut(&&values: [mut T]) { let mut i = values.len(); while i >= 2u { // invariant: elements with index >= i have been locked in place. diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 7f967ae373d7..6c24b6569884 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -122,7 +122,7 @@ Convert a vector of bytes to a UTF-8 string Fails if invalid UTF-8 "] -fn from_bytes(vv: [u8]) -> str unsafe { +pure fn from_bytes(vv: [u8]) -> str unsafe { assert is_utf8(vv); ret unsafe::from_bytes(vv); } @@ -134,7 +134,7 @@ Convert a byte to a UTF-8 string Fails if invalid UTF-8 "] -fn from_byte(b: u8) -> str unsafe { +pure fn from_byte(b: u8) -> str unsafe { assert b < 128u8; let mut v = [b, 0u8]; let s: str = ::unsafe::reinterpret_cast(v); @@ -217,22 +217,24 @@ fn push_char(&s: str, ch: char) unsafe { } #[doc = "Convert a char to a string"] -fn from_char(ch: char) -> str { +pure fn from_char(ch: char) -> str { let mut buf = ""; - push_char(buf, ch); + unchecked { push_char(buf, ch); } ret buf; } #[doc = "Convert a vector of chars to a string"] -fn from_chars(chs: [char]) -> str { +pure fn from_chars(chs: [char]) -> str { let mut buf = ""; - reserve(buf, chs.len()); - for vec::each(chs) {|ch| push_char(buf, ch); } + unchecked { + reserve(buf, chs.len()); + for vec::each(chs) {|ch| push_char(buf, ch); } + } ret buf; } #[doc = "Concatenate a vector of strings"] -fn concat(v: [str]) -> str { +pure fn concat(v: [str]) -> str { let mut s: str = ""; for vec::each(v) {|ss| s += ss; } ret s; @@ -241,7 +243,7 @@ fn concat(v: [str]) -> str { #[doc = " Concatenate a vector of strings, placing a given separator between each "] -fn connect(v: [str], sep: str) -> str { +pure fn connect(v: [str], sep: str) -> str { let mut s = "", first = true; for vec::each(v) {|ss| if first { first = false; } else { s += sep; } @@ -286,7 +288,7 @@ fn shift_char(&s: str) -> char unsafe { fn unshift_char(&s: str, ch: char) { s = from_char(ch) + s; } #[doc = "Returns a string with leading whitespace removed"] -fn trim_left(+s: str) -> str { +pure fn trim_left(+s: str) -> str { alt find(s, {|c| !char::is_whitespace(c)}) { none { "" } some(first) { @@ -297,7 +299,7 @@ fn trim_left(+s: str) -> str { } #[doc = "Returns a string with trailing whitespace removed"] -fn trim_right(+s: str) -> str { +pure fn trim_right(+s: str) -> str { alt rfind(s, {|c| !char::is_whitespace(c)}) { none { "" } some(last) { @@ -309,7 +311,7 @@ fn trim_right(+s: str) -> str { } #[doc = "Returns a string with leading and trailing whitespace removed"] -fn trim(+s: str) -> str { trim_left(trim_right(s)) } +pure fn trim(+s: str) -> str { trim_left(trim_right(s)) } /* Section: Transforming strings @@ -320,7 +322,7 @@ Converts a string to a vector of bytes The result vector is not null-terminated. "] -fn bytes(s: str) -> [u8] unsafe { +pure fn bytes(s: str) -> [u8] unsafe { let mut s_copy = s; let mut v: [u8] = ::unsafe::reinterpret_cast(s_copy); ::unsafe::forget(s_copy); @@ -332,14 +334,14 @@ fn bytes(s: str) -> [u8] unsafe { Work with the string as a byte slice, not including trailing null. "] #[inline(always)] -fn byte_slice(s: str/&, f: fn([u8]/&) -> T) -> T unsafe { +pure fn byte_slice(s: str/&, f: fn([u8]/&) -> T) -> T unsafe { unpack_slice(s) {|p,n| vec::unsafe::form_slice(p, n-1u, f) } } #[doc = "Convert a string to a vector of characters"] -fn chars(s: str) -> [char] { +pure fn chars(s: str) -> [char] { let mut buf = [], i = 0u; let len = len(s); while i < len { @@ -356,7 +358,7 @@ Take a substring of another. Returns a string containing `n` characters starting at byte offset `begin`. "] -fn substr(s: str, begin: uint, n: uint) -> str { +pure fn substr(s: str, begin: uint, n: uint) -> str { slice(s, begin, begin + count_bytes(s, begin, n)) } @@ -366,7 +368,7 @@ Returns a slice of the given string from the byte range [`begin`..`end`) Fails when `begin` and `end` do not point to valid characters or beyond the last character of the string "] -fn slice(s: str, begin: uint, end: uint) -> str unsafe { +pure fn slice(s: str, begin: uint, end: uint) -> str unsafe { assert is_char_boundary(s, begin); assert is_char_boundary(s, end); unsafe::slice_bytes(s, begin, end) @@ -375,7 +377,7 @@ fn slice(s: str, begin: uint, end: uint) -> str unsafe { #[doc = " Splits a string into substrings at each occurrence of a given character "] -fn split_char(s: str, sep: char) -> [str] { +pure fn split_char(s: str, sep: char) -> [str] { split_char_inner(s, sep, len(s), true) } @@ -385,18 +387,18 @@ character up to 'count' times The byte must be a valid UTF-8/ASCII byte "] -fn splitn_char(s: str, sep: char, count: uint) -> [str] { +pure fn splitn_char(s: str, sep: char, count: uint) -> [str] { split_char_inner(s, sep, count, true) } #[doc = " Like `split_char`, but omits empty strings from the returned vector "] -fn split_char_nonempty(s: str, sep: char) -> [str] { +pure fn split_char_nonempty(s: str, sep: char) -> [str] { split_char_inner(s, sep, len(s), false) } -fn split_char_inner(s: str, sep: char, count: uint, allow_empty: bool) +pure fn split_char_inner(s: str, sep: char, count: uint, allow_empty: bool) -> [str] unsafe { if sep < 128u as char { let b = sep as u8, l = len(s); @@ -423,7 +425,7 @@ fn split_char_inner(s: str, sep: char, count: uint, allow_empty: bool) #[doc = "Splits a string into substrings using a character function"] -fn split(s: str, sepfn: fn(char) -> bool) -> [str] { +pure fn split(s: str, sepfn: fn(char) -> bool) -> [str] { split_inner(s, sepfn, len(s), true) } @@ -431,16 +433,16 @@ fn split(s: str, sepfn: fn(char) -> bool) -> [str] { Splits a string into substrings using a character function, cutting at most `count` times. "] -fn splitn(s: str, sepfn: fn(char) -> bool, count: uint) -> [str] { +pure fn splitn(s: str, sepfn: fn(char) -> bool, count: uint) -> [str] { split_inner(s, sepfn, count, true) } #[doc = "Like `split`, but omits empty strings from the returned vector"] -fn split_nonempty(s: str, sepfn: fn(char) -> bool) -> [str] { +pure fn split_nonempty(s: str, sepfn: fn(char) -> bool) -> [str] { split_inner(s, sepfn, len(s), false) } -fn split_inner(s: str, sepfn: fn(cc: char) -> bool, count: uint, +pure fn split_inner(s: str, sepfn: fn(cc: char) -> bool, count: uint, allow_empty: bool) -> [str] unsafe { let l = len(s); let mut result = [], i = 0u, start = 0u, done = 0u; @@ -462,7 +464,7 @@ fn split_inner(s: str, sepfn: fn(cc: char) -> bool, count: uint, } // See Issue #1932 for why this is a naive search -fn iter_matches(s: str, sep: str, f: fn(uint, uint)) { +pure fn iter_matches(s: str, sep: str, f: fn(uint, uint)) { let sep_len = len(sep), l = len(s); assert sep_len > 0u; let mut i = 0u, match_start = 0u, match_i = 0u; @@ -489,7 +491,7 @@ fn iter_matches(s: str, sep: str, f: fn(uint, uint)) { } } -fn iter_between_matches(s: str, sep: str, f: fn(uint, uint)) { +pure fn iter_between_matches(s: str, sep: str, f: fn(uint, uint)) { let mut last_end = 0u; iter_matches(s, sep) {|from, to| f(last_end, from); @@ -507,7 +509,7 @@ Splits a string into a vector of the substrings separated by a given string assert [\"\", \"XXX\", \"YYY\", \"\"] == split_str(\".XXX.YYY.\", \".\") ~~~ "] -fn split_str(s: str, sep: str) -> [str] { +pure fn split_str(s: str, sep: str) -> [str] { let mut result = []; iter_between_matches(s, sep) {|from, to| unsafe { result += [unsafe::slice_bytes(s, from, to)]; } @@ -515,7 +517,7 @@ fn split_str(s: str, sep: str) -> [str] { result } -fn split_str_nonempty(s: str, sep: str) -> [str] { +pure fn split_str_nonempty(s: str, sep: str) -> [str] { let mut result = []; iter_between_matches(s, sep) {|from, to| if to > from { @@ -528,13 +530,13 @@ fn split_str_nonempty(s: str, sep: str) -> [str] { #[doc = " Splits a string into a vector of the substrings separated by LF ('\\n') "] -fn lines(s: str) -> [str] { split_char(s, '\n') } +pure fn lines(s: str) -> [str] { split_char(s, '\n') } #[doc = " Splits a string into a vector of the substrings separated by LF ('\\n') and/or CR LF ('\\r\\n') "] -fn lines_any(s: str) -> [str] { +pure fn lines_any(s: str) -> [str] { vec::map(lines(s), {|s| let l = len(s); let mut cp = s; @@ -548,18 +550,22 @@ fn lines_any(s: str) -> [str] { #[doc = " Splits a string into a vector of the substrings separated by whitespace "] -fn words(s: str) -> [str] { +pure fn words(s: str) -> [str] { split_nonempty(s, {|c| char::is_whitespace(c)}) } #[doc = "Convert a string to lowercase. ASCII only"] -fn to_lower(s: str) -> str { - map(s, {|c| (libc::tolower(c as libc::c_char)) as char}) +pure fn to_lower(s: str) -> str { + map(s, {|c| + unchecked{(libc::tolower(c as libc::c_char)) as char} + }) } #[doc = "Convert a string to uppercase. ASCII only"] -fn to_upper(s: str) -> str { - map(s, {|c| (libc::toupper(c as libc::c_char)) as char}) +pure fn to_upper(s: str) -> str { + map(s, {|c| + unchecked{(libc::toupper(c as libc::c_char)) as char} + }) } #[doc = " @@ -575,7 +581,7 @@ Replace all occurances of one string with another The original string with all occurances of `from` replaced with `to` "] -fn replace(s: str, from: str, to: str) -> str unsafe { +pure fn replace(s: str, from: str, to: str) -> str unsafe { let mut result = "", first = true; iter_between_matches(s, from) {|start, end| if first { first = false; } else { result += to; } @@ -595,7 +601,7 @@ pure fn eq(&&a: str, &&b: str) -> bool { a == b } pure fn le(&&a: str, &&b: str) -> bool { a <= b } #[doc = "String hash function"] -fn hash(&&s: str) -> uint { +pure fn hash(&&s: str) -> uint { // djb hash. // FIXME: replace with murmur. (see #859 and #1616) let mut u: uint = 5381u; @@ -611,7 +617,7 @@ Section: Iterating through strings Return true if a predicate matches all characters or if the string contains no characters "] -fn all(s: str, it: fn(char) -> bool) -> bool { +pure fn all(s: str, it: fn(char) -> bool) -> bool { all_between(s, 0u, len(s), it) } @@ -619,20 +625,24 @@ fn all(s: str, it: fn(char) -> bool) -> bool { Return true if a predicate matches any character (and false if it matches none or there are no characters) "] -fn any(ss: str, pred: fn(char) -> bool) -> bool { +pure fn any(ss: str, pred: fn(char) -> bool) -> bool { !all(ss, {|cc| !pred(cc)}) } #[doc = "Apply a function to each character"] -fn map(ss: str, ff: fn(char) -> char) -> str { +pure fn map(ss: str, ff: fn(char) -> char) -> str { let mut result = ""; - reserve(result, len(ss)); - chars_iter(ss) {|cc| str::push_char(result, ff(cc));} + unchecked { + reserve(result, len(ss)); + chars_iter(ss) {|cc| + str::push_char(result, ff(cc)); + } + } result } #[doc = "Iterate over the bytes in a string"] -fn bytes_iter(ss: str, it: fn(u8)) { +pure fn bytes_iter(ss: str, it: fn(u8)) { let mut pos = 0u; let len = len(ss); @@ -644,7 +654,7 @@ fn bytes_iter(ss: str, it: fn(u8)) { #[doc = "Iterate over the bytes in a string"] #[inline(always)] -fn each(s: str, it: fn(u8) -> bool) { +pure fn each(s: str, it: fn(u8) -> bool) { let mut i = 0u, l = len(s); while (i < l) { if !it(s[i]) { break; } @@ -654,7 +664,7 @@ fn each(s: str, it: fn(u8) -> bool) { #[doc = "Iterates over the chars in a string"] #[inline(always)] -fn each_char(s: str, it: fn(char) -> bool) { +pure fn each_char(s: str, it: fn(char) -> bool) { let mut pos = 0u; let len = len(s); while pos < len { @@ -665,7 +675,7 @@ fn each_char(s: str, it: fn(char) -> bool) { } #[doc = "Iterate over the characters in a string"] -fn chars_iter(s: str, it: fn(char)) { +pure fn chars_iter(s: str, it: fn(char)) { let mut pos = 0u; let len = len(s); while (pos < len) { @@ -678,7 +688,7 @@ fn chars_iter(s: str, it: fn(char)) { #[doc = " Apply a function to each substring after splitting by character "] -fn split_char_iter(ss: str, cc: char, ff: fn(&&str)) { +pure fn split_char_iter(ss: str, cc: char, ff: fn(&&str)) { vec::iter(split_char(ss, cc), ff) } @@ -686,17 +696,18 @@ fn split_char_iter(ss: str, cc: char, ff: fn(&&str)) { Apply a function to each substring after splitting by character, up to `count` times "] -fn splitn_char_iter(ss: str, sep: char, count: uint, ff: fn(&&str)) unsafe { +pure fn splitn_char_iter(ss: str, sep: char, count: uint, + ff: fn(&&str)) unsafe { vec::iter(splitn_char(ss, sep, count), ff) } #[doc = "Apply a function to each word"] -fn words_iter(ss: str, ff: fn(&&str)) { +pure fn words_iter(ss: str, ff: fn(&&str)) { vec::iter(words(ss), ff) } #[doc = "Apply a function to each line (by '\\n')"] -fn lines_iter(ss: str, ff: fn(&&str)) { +pure fn lines_iter(ss: str, ff: fn(&&str)) { vec::iter(lines(ss), ff) } @@ -717,7 +728,7 @@ Returns the byte index of the first matching character An `option` containing the byte index of the first matching character or `none` if there is no match "] -fn find_char(s: str, c: char) -> option { +pure fn find_char(s: str, c: char) -> option { find_char_between(s, c, 0u, len(s)) } @@ -741,7 +752,7 @@ or `none` if there is no match `start` must be less than or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn find_char_from(s: str, c: char, start: uint) -> option { +pure fn find_char_from(s: str, c: char, start: uint) -> option { find_char_between(s, c, start, len(s)) } @@ -766,7 +777,7 @@ or `none` if there is no match or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn find_char_between(s: str, c: char, start: uint, end: uint) +pure fn find_char_between(s: str, c: char, start: uint, end: uint) -> option { if c < 128u as char { assert start <= end; @@ -796,7 +807,7 @@ Returns the byte index of the last matching character An `option` containing the byte index of the last matching character or `none` if there is no match "] -fn rfind_char(s: str, c: char) -> option { +pure fn rfind_char(s: str, c: char) -> option { rfind_char_between(s, c, len(s), 0u) } @@ -820,7 +831,7 @@ or `none` if there is no match `start` must be less than or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn rfind_char_from(s: str, c: char, start: uint) -> option { +pure fn rfind_char_from(s: str, c: char, start: uint) -> option { rfind_char_between(s, c, start, 0u) } @@ -845,7 +856,7 @@ or `none` if there is no match or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn rfind_char_between(s: str, c: char, start: uint, end: uint) +pure fn rfind_char_between(s: str, c: char, start: uint, end: uint) -> option { if c < 128u as char { assert start >= end; @@ -876,7 +887,7 @@ the given predicate An `option` containing the byte index of the first matching character or `none` if there is no match "] -fn find(s: str, f: fn(char) -> bool) -> option { +pure fn find(s: str, f: fn(char) -> bool) -> option { find_between(s, 0u, len(s), f) } @@ -900,7 +911,7 @@ or `none` if there is no match `start` must be less than or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn find_from(s: str, start: uint, f: fn(char) -> bool) -> option { +pure fn find_from(s: str, start: uint, f: fn(char) -> bool) -> option { find_between(s, start, len(s), f) } @@ -926,7 +937,7 @@ or `none` if there is no match or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary`. "] -fn find_between(s: str, start: uint, end: uint, f: fn(char) -> bool) +pure fn find_between(s: str, start: uint, end: uint, f: fn(char) -> bool) -> option { assert start <= end; assert end <= len(s); @@ -954,7 +965,7 @@ the given predicate An option containing the byte index of the last matching character or `none` if there is no match "] -fn rfind(s: str, f: fn(char) -> bool) -> option { +pure fn rfind(s: str, f: fn(char) -> bool) -> option { rfind_between(s, len(s), 0u, f) } @@ -978,7 +989,7 @@ or `none` if there is no match `start` must be less than or equal to `len(s)', `start` must be the index of a character boundary, as defined by `is_char_boundary` "] -fn rfind_from(s: str, start: uint, f: fn(char) -> bool) -> option { +pure fn rfind_from(s: str, start: uint, f: fn(char) -> bool) -> option { rfind_between(s, start, 0u, f) } @@ -1004,7 +1015,7 @@ or `none` if there is no match than or equal to `len(s)`. `start` must be the index of a character boundary, as defined by `is_char_boundary` "] -fn rfind_between(s: str, start: uint, end: uint, f: fn(char) -> bool) +pure fn rfind_between(s: str, start: uint, end: uint, f: fn(char) -> bool) -> option { assert start >= end; assert start <= len(s); @@ -1019,7 +1030,7 @@ fn rfind_between(s: str, start: uint, end: uint, f: fn(char) -> bool) } // Utility used by various searching functions -fn match_at(haystack: str, needle: str, at: uint) -> bool { +pure fn match_at(haystack: str, needle: str, at: uint) -> bool { let mut i = at; for each(needle) {|c| if haystack[i] != c { ret false; } i += 1u; } ret true; @@ -1038,7 +1049,7 @@ Returns the byte index of the first matching substring An `option` containing the byte index of the first matching substring or `none` if there is no match "] -fn find_str(haystack: str, needle: str) -> option { +pure fn find_str(haystack: str, needle: str) -> option { find_str_between(haystack, needle, 0u, len(haystack)) } @@ -1061,7 +1072,7 @@ or `none` if there is no match `start` must be less than or equal to `len(s)` "] -fn find_str_from(haystack: str, needle: str, start: uint) +pure fn find_str_from(haystack: str, needle: str, start: uint) -> option { find_str_between(haystack, needle, start, len(haystack)) } @@ -1086,7 +1097,7 @@ or `none` if there is no match `start` must be less than or equal to `end` and `end` must be less than or equal to `len(s)`. "] -fn find_str_between(haystack: str, needle: str, start: uint, end:uint) +pure fn find_str_between(haystack: str, needle: str, start: uint, end:uint) -> option { // See Issue #1932 for why this is a naive search assert end <= len(haystack); @@ -1111,7 +1122,7 @@ Returns true if one string contains another * haystack - The string to look in * needle - The string to look for "] -fn contains(haystack: str, needle: str) -> bool { +pure fn contains(haystack: str, needle: str) -> bool { option::is_some(find_str(haystack, needle)) } @@ -1123,7 +1134,7 @@ Returns true if one string starts with another * haystack - The string to look in * needle - The string to look for "] -fn starts_with(haystack: str, needle: str) -> bool unsafe { +pure fn starts_with(haystack: str, needle: str) -> bool unsafe { let haystack_len = len(haystack), needle_len = len(needle); if needle_len == 0u { true } else if needle_len > haystack_len { false } @@ -1138,7 +1149,7 @@ Returns true if one string ends with another * haystack - The string to look in * needle - The string to look for "] -fn ends_with(haystack: str, needle: str) -> bool { +pure fn ends_with(haystack: str, needle: str) -> bool { let haystack_len = len(haystack), needle_len = len(needle); if needle_len == 0u { true } else if needle_len > haystack_len { false } @@ -1150,7 +1161,7 @@ Section: String properties */ #[doc = "Determines if a string contains only ASCII characters"] -fn is_ascii(s: str) -> bool { +pure fn is_ascii(s: str) -> bool { let mut i: uint = len(s); while i > 0u { i -= 1u; if !u8::is_ascii(s[i]) { ret false; } } ret true; @@ -1167,7 +1178,7 @@ Returns true if the string contains only whitespace Whitespace characters are determined by `char::is_whitespace` "] -fn is_whitespace(s: str) -> bool { +pure fn is_whitespace(s: str) -> bool { ret all(s, char::is_whitespace); } @@ -1189,14 +1200,14 @@ pure fn len(s: str) -> uint unsafe { } #[doc = "Returns the number of characters that a string holds"] -fn char_len(s: str) -> uint { count_chars(s, 0u, len(s)) } +pure fn char_len(s: str) -> uint { count_chars(s, 0u, len(s)) } /* Section: Misc */ #[doc = "Determines if a vector of bytes contains valid UTF-8"] -fn is_utf8(v: [const u8]) -> bool { +pure fn is_utf8(v: [const u8]) -> bool { let mut i = 0u; let total = vec::len::(v); while i < total { @@ -1214,7 +1225,7 @@ fn is_utf8(v: [const u8]) -> bool { } #[doc = "Determines if a vector of `u16` contains valid UTF-16"] -fn is_utf16(v: [const u16]) -> bool { +pure fn is_utf16(v: [const u16]) -> bool { let len = vec::len(v); let mut i = 0u; while (i < len) { @@ -1235,7 +1246,7 @@ fn is_utf16(v: [const u16]) -> bool { } #[doc = "Converts to a vector of `u16` encoded as UTF-16"] -fn to_utf16(s: str) -> [u16] { +pure fn to_utf16(s: str) -> [u16] { let mut u = []; chars_iter(s) {|cch| // Arithmetic with u32 literals is easier on the eyes than chars. @@ -1257,7 +1268,7 @@ fn to_utf16(s: str) -> [u16] { ret u; } -fn utf16_chars(v: [const u16], f: fn(char)) { +pure fn utf16_chars(v: [const u16], f: fn(char)) { let len = vec::len(v); let mut i = 0u; while (i < len && v[i] != 0u16) { @@ -1282,10 +1293,12 @@ fn utf16_chars(v: [const u16], f: fn(char)) { } -fn from_utf16(v: [const u16]) -> str { +pure fn from_utf16(v: [const u16]) -> str { let mut buf = ""; - reserve(buf, vec::len(v)); - utf16_chars(v) {|ch| push_char(buf, ch); } + unchecked { + reserve(buf, vec::len(v)); + utf16_chars(v) {|ch| push_char(buf, ch); } + } ret buf; } @@ -1303,7 +1316,7 @@ As char_len but for a slice of a string The number of Unicode characters in `s` between the given indices. "] -fn count_chars(s: str, start: uint, end: uint) -> uint { +pure fn count_chars(s: str, start: uint, end: uint) -> uint { assert is_char_boundary(s, start); assert is_char_boundary(s, end); let mut i = start, len = 0u; @@ -1318,7 +1331,7 @@ fn count_chars(s: str, start: uint, end: uint) -> uint { #[doc = " Counts the number of bytes taken by the `n` in `s` starting from `start`. "] -fn count_bytes(s: str, start: uint, n: uint) -> uint { +pure fn count_bytes(s: str, start: uint, n: uint) -> uint { assert is_char_boundary(s, start); let mut end = start, cnt = n; let l = len(s); @@ -1403,7 +1416,7 @@ index of the next unicode character. If `i` is greater than or equal to the length of the string. If `i` is not the index of the beginning of a valid UTF-8 character. "] -fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} { +pure fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} { let b0 = s[i]; let w = utf8_char_width(b0); assert (w != 0u); @@ -1426,14 +1439,16 @@ fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} { } #[doc = "Pluck a character out of a string"] -fn char_at(s: str, i: uint) -> char { ret char_range_at(s, i).ch; } +pure fn char_at(s: str, i: uint) -> char { ret char_range_at(s, i).ch; } #[doc = " Given a byte position and a str, return the previous char and its position This function can be used to iterate over a unicode string in reverse. "] -fn char_range_at_reverse(ss: str, start: uint) -> {ch: char, prev: uint} { +pure fn char_range_at_reverse(ss: str, start: uint) + -> {ch: char, prev: uint} { + let mut prev = start; // while there is a previous byte == 10...... @@ -1470,7 +1485,8 @@ Loop through a substring, char by char `true` If execution proceeded correctly, `false` if it was interrupted, that is if `it` returned `false` at any point. "] -fn all_between(s: str, start: uint, end: uint, it: fn(char) -> bool) -> bool { +pure fn all_between(s: str, start: uint, end: uint, + it: fn(char) -> bool) -> bool { assert is_char_boundary(s, start); let mut i = start; while i < end { @@ -1502,7 +1518,8 @@ Loop through a substring, char by char `true` if `it` returns `true` for any character "] -fn any_between(s: str, start: uint, end: uint, it: fn(char) -> bool) -> bool { +pure fn any_between(s: str, start: uint, end: uint, + it: fn(char) -> bool) -> bool { !all_between(s, start, end, {|c| !it(c)}) } @@ -1533,7 +1550,7 @@ interop. let i = str::as_bytes(\"Hello World\") { |bytes| vec::len(bytes) }; ~~~ "] -fn as_bytes(s: str, f: fn([u8]) -> T) -> T unsafe { +pure fn as_bytes(s: str, f: fn([u8]) -> T) -> T unsafe { let v: *[u8] = ::unsafe::reinterpret_cast(ptr::addr_of(s)); f(*v) } @@ -1544,7 +1561,7 @@ Work with the byte buffer of a string. Allows for unsafe manipulation of strings, which is useful for native interop. "] -fn as_buf(s: str, f: fn(*u8) -> T) -> T unsafe { +pure fn as_buf(s: str, f: fn(*u8) -> T) -> T unsafe { as_bytes(s) { |v| vec::as_buf(v, f) } } @@ -1560,7 +1577,7 @@ interop, without copying the original string. let s = str::as_buf(\"PATH\", { |path_buf| libc::getenv(path_buf) }); ~~~ "] -fn as_c_str(s: str, f: fn(*libc::c_char) -> T) -> T unsafe { +pure fn as_c_str(s: str, f: fn(*libc::c_char) -> T) -> T unsafe { as_buf(s) {|buf| f(buf as *libc::c_char) } } @@ -1574,7 +1591,7 @@ indexable area for a null byte, as is the case in slices pointing to full strings, or suffixes of them. "] #[inline(always)] -fn unpack_slice(s: str/&, f: fn(*u8, uint) -> T) -> T unsafe { +pure fn unpack_slice(s: str/&, f: fn(*u8, uint) -> T) -> T unsafe { let v : *(*u8,uint) = ::unsafe::reinterpret_cast(ptr::addr_of(s)); let (buf,len) = *v; f(buf, len) @@ -1639,18 +1656,22 @@ pure fn capacity(&&s: str) -> uint unsafe { } #[doc = "Escape each char in `s` with char::escape_default."] -fn escape_default(s: str) -> str { +pure fn escape_default(s: str) -> str { let mut out: str = ""; - reserve_at_least(out, str::len(s)); - chars_iter(s) {|c| out += char::escape_default(c); } + unchecked { + reserve_at_least(out, str::len(s)); + chars_iter(s) {|c| out += char::escape_default(c); } + } ret out; } #[doc = "Escape each char in `s` with char::escape_unicode."] -fn escape_unicode(s: str) -> str { +pure fn escape_unicode(s: str) -> str { let mut out: str = ""; - reserve_at_least(out, str::len(s)); - chars_iter(s) {|c| out += char::escape_unicode(c); } + unchecked { + reserve_at_least(out, str::len(s)); + chars_iter(s) {|c| out += char::escape_unicode(c); } + } ret out; } diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index cce654f0e24b..8247ad5b262a 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -798,7 +798,7 @@ Swaps two elements in a vector * a - The index of the first element * b - The index of the second element "] -fn swap(v: [mut T], a: uint, b: uint) { +fn swap(&&v: [mut T], a: uint, b: uint) { v[a] <-> v[b]; } @@ -1221,12 +1221,12 @@ mod unsafe { #[doc = " Sets the length of a vector - This well explicitly set the size of the vector, without actually + This will explicitly set the size of the vector, without actually modifing its buffers, so it is up to the caller to ensure that the vector is actually the specified size. "] #[inline(always)] - unsafe fn set_len(&v: [const T], new_len: uint) { + unsafe fn set_len(&&v: [const T], new_len: uint) { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); (**repr).fill = new_len * sys::size_of::(); } From c3b266f50f5f7a05761a06fbe30c14451e86ca31 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Jun 2012 07:36:01 -0700 Subject: [PATCH 33/53] Rewrite deque to use dvec --- src/libstd/deque.rs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index 0f30e5e6e12c..4cef32456618 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -1,6 +1,7 @@ #[doc = "A deque. Untested as of yet. Likely buggy"]; import option::{some, none}; +import dvec::{dvec, extensions}; iface t { fn size() -> uint; @@ -23,7 +24,7 @@ fn create() -> t { * Grow is only called on full elts, so nelts is also len(elts), unlike * elsewhere. */ - fn grow(nelts: uint, lo: uint, elts: [mut cell]) -> + fn grow(nelts: uint, lo: uint, -elts: [mut cell]) -> [mut cell] { assert (nelts == vec::len(elts)); let mut rv = [mut]; @@ -39,38 +40,38 @@ fn create() -> t { ret rv; } - fn get(elts: [mut cell], i: uint) -> T { - ret alt elts[i] { some(t) { t } _ { fail } }; + fn get(elts: dvec>, i: uint) -> T { + alt elts.get_elt(i) { some(t) { t } _ { fail } } } type repr = {mut nelts: uint, mut lo: uint, mut hi: uint, - mut elts: [mut cell]}; + elts: dvec>}; impl of t for repr { fn size() -> uint { ret self.nelts; } fn add_front(t: T) { let oldlo: uint = self.lo; if self.lo == 0u { - self.lo = vec::len(self.elts) - 1u; + self.lo = self.elts.len() - 1u; } else { self.lo -= 1u; } if self.lo == self.hi { - self.elts = grow(self.nelts, oldlo, self.elts); - self.lo = vec::len(self.elts) - 1u; + self.elts.swap({ |v| grow(self.nelts, oldlo, v) }); + self.lo = self.elts.len() - 1u; self.hi = self.nelts; } - self.elts[self.lo] = some(t); + self.elts.set_elt(self.lo, some(t)); self.nelts += 1u; } fn add_back(t: T) { if self.lo == self.hi && self.nelts != 0u { - self.elts = grow(self.nelts, self.lo, self.elts); + self.elts.swap({ |v| grow(self.nelts, self.lo, v) }); self.lo = 0u; self.hi = self.nelts; } - self.elts[self.hi] = some(t); - self.hi = (self.hi + 1u) % vec::len(self.elts); + self.elts.set_elt(self.hi, some(t)); + self.hi = (self.hi + 1u) % self.elts.len(); self.nelts += 1u; } /** @@ -79,24 +80,24 @@ fn create() -> t { */ fn pop_front() -> T { let t: T = get(self.elts, self.lo); - self.elts[self.lo] = none; - self.lo = (self.lo + 1u) % vec::len(self.elts); + self.elts.set_elt(self.lo, none); + self.lo = (self.lo + 1u) % self.elts.len(); self.nelts -= 1u; ret t; } fn pop_back() -> T { if self.hi == 0u { - self.hi = vec::len(self.elts) - 1u; + self.hi = self.elts.len() - 1u; } else { self.hi -= 1u; } let t: T = get(self.elts, self.hi); - self.elts[self.hi] = none; + self.elts.set_elt(self.hi, none); self.nelts -= 1u; ret t; } fn peek_front() -> T { ret get(self.elts, self.lo); } fn peek_back() -> T { ret get(self.elts, self.hi - 1u); } fn get(i: int) -> T { - let idx = (self.lo + (i as uint)) % vec::len(self.elts); + let idx = (self.lo + (i as uint)) % self.elts.len(); ret get(self.elts, idx); } } @@ -105,7 +106,10 @@ fn create() -> t { mut nelts: 0u, mut lo: 0u, mut hi: 0u, - mut elts: vec::to_mut(vec::from_elem(initial_capacity, none)) + elts: + dvec::from_vec( + vec::to_mut( + vec::from_elem(initial_capacity, none))) }; repr as t:: } From 45680c83ab81986bbedf93878e3d24f69be02981 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Jun 2012 07:36:40 -0700 Subject: [PATCH 34/53] borrowck changes: some copies, some removed mut annotations, some dvec --- src/libsyntax/ext/simplext.rs | 11 ++++++----- src/libsyntax/parse/common.rs | 13 +++++++------ src/libsyntax/parse/parser.rs | 30 +++++++++++++++--------------- src/libsyntax/print/pp.rs | 26 +++++++++++++------------- src/libsyntax/print/pprust.rs | 2 +- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/libsyntax/ext/simplext.rs b/src/libsyntax/ext/simplext.rs index 76b78cb2b86c..764c484c8e39 100644 --- a/src/libsyntax/ext/simplext.rs +++ b/src/libsyntax/ext/simplext.rs @@ -1,5 +1,6 @@ import codemap::span; import std::map::{hashmap, str_hash}; +import dvec::{dvec, extensions}; import base::*; @@ -134,7 +135,7 @@ fn compose_sels(s1: selector, s2: selector) -> selector { type binders = {real_binders: hashmap, - mut literal_ast_matchers: [selector]}; + literal_ast_matchers: dvec}; type bindings = hashmap>; fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { } @@ -146,7 +147,7 @@ fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { } fn pattern_to_selectors(cx: ext_ctxt, e: @expr) -> binders { let res: binders = {real_binders: str_hash::(), - mut literal_ast_matchers: []}; + literal_ast_matchers: dvec()}; //this oughta return binders instead, but macro args are a sequence of //expressions, rather than a single expression fn trivial_selector(m: matchable) -> match_result { ret some(leaf(m)); } @@ -474,7 +475,7 @@ fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) { _ { cx.bug("broken traversal in p_t_s_r") } } } - b.literal_ast_matchers += [bind select(cx, _, e)]; + b.literal_ast_matchers.push(bind select(cx, _, e)); } } } @@ -640,8 +641,8 @@ fn p_t_s_r_length(cx: ext_ctxt, len: uint, at_least: bool, s: selector, _ { none } } } - b.literal_ast_matchers += - [compose_sels(s, bind len_select(cx, _, at_least, len))]; + b.literal_ast_matchers.push( + compose_sels(s, bind len_select(cx, _, at_least, len))); } fn p_t_s_r_actual_vector(cx: ext_ctxt, elts: [@expr], _repeat_after: bool, diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 4bfba482c4f5..05e14c4654df 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -18,7 +18,7 @@ fn seq_sep_none() -> seq_sep { } -fn token_to_str(reader: reader, token: token::token) -> str { +fn token_to_str(reader: reader, ++token: token::token) -> str { token::to_str(*reader.interner, token) } @@ -27,8 +27,9 @@ fn token_to_str(reader: reader, token: token::token) -> str { impl parser_common for parser { fn unexpected_last(t: token::token) -> ! { - self.span_fatal(self.last_span, "unexpected token: '" - + token_to_str(self.reader, t) + "'"); + self.span_fatal( + copy self.last_span, + "unexpected token: '" + token_to_str(self.reader, t) + "'"); } fn unexpected() -> ! { @@ -49,7 +50,7 @@ impl parser_common for parser { } fn parse_ident() -> ast::ident { - alt self.token { + alt copy self.token { token::IDENT(i, _) { self.bump(); ret self.get_str(i); } _ { self.fatal("expecting ident, found " + token_to_str(self.reader, self.token)); } @@ -79,7 +80,7 @@ impl parser_common for parser { } } - fn token_is_keyword(word: str, tok: token::token) -> bool { + fn token_is_keyword(word: str, ++tok: token::token) -> bool { self.require_keyword(word); alt tok { token::IDENT(sid, false) { str::eq(word, self.get_str(sid)) } @@ -93,7 +94,7 @@ impl parser_common for parser { fn eat_keyword(word: str) -> bool { self.require_keyword(word); - alt self.token { + alt copy self.token { token::IDENT(sid, false) { if str::eq(word, self.get_str(sid)) { self.bump(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8b40e2a8a973..33e7d082bfb0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -121,16 +121,16 @@ class parser { ret self.buffer[distance - 1u].tok; } fn fatal(m: str) -> ! { - self.sess.span_diagnostic.span_fatal(self.span, m) + self.sess.span_diagnostic.span_fatal(copy self.span, m) } fn span_fatal(sp: span, m: str) -> ! { self.sess.span_diagnostic.span_fatal(sp, m) } fn bug(m: str) -> ! { - self.sess.span_diagnostic.span_bug(self.span, m) + self.sess.span_diagnostic.span_bug(copy self.span, m) } fn warn(m: str) { - self.sess.span_diagnostic.span_warn(self.span, m) + self.sess.span_diagnostic.span_warn(copy self.span, m) } fn get_str(i: token::str_num) -> str { interner::get(*self.reader.interner, i) @@ -307,7 +307,7 @@ class parser { // Parses something like "&x" fn parse_region() -> @region { self.expect(token::BINOP(token::AND)); - alt self.token { + alt copy self.token { token::IDENT(sid, _) { self.bump(); let n = self.get_str(sid); @@ -322,7 +322,7 @@ class parser { // Parses something like "&x." (note the trailing dot) fn parse_region_dot() -> @region { let name = - alt self.token { + alt copy self.token { token::IDENT(sid, _) if self.look_ahead(1u) == token::DOT { self.bump(); self.bump(); some(self.get_str(sid)) @@ -483,11 +483,11 @@ class parser { } fn maybe_parse_dollar_mac() -> option { - alt self.token { + alt copy self.token { token::DOLLAR { let lo = self.span.lo; self.bump(); - alt self.token { + alt copy self.token { token::LIT_INT(num, ty_i) { self.bump(); some(mac_var(num as uint)) @@ -511,7 +511,7 @@ class parser { fn maybe_parse_vstore() -> option { if self.token == token::BINOP(token::SLASH) { self.bump(); - alt self.token { + alt copy self.token { token::AT { self.bump(); some(vstore_box) } @@ -968,7 +968,7 @@ class parser { loop { // expr.f if self.eat(token::DOT) { - alt self.token { + alt copy self.token { token::IDENT(i, _) { hi = self.span.hi; self.bump(); @@ -986,7 +986,7 @@ class parser { cont; } if self.expr_is_complete(e) { break; } - alt self.token { + alt copy self.token { // expr(...) token::LPAREN if self.permits_call() { let es_opt = self.parse_seq(token::LPAREN, token::RPAREN, @@ -1042,7 +1042,7 @@ class parser { let mut hi; let mut ex; - alt self.token { + alt copy self.token { token::NOT { self.bump(); let e = self.to_expr(self.parse_prefix_expr()); @@ -1134,7 +1134,7 @@ class parser { fn parse_assign_expr() -> @expr { let lo = self.span.lo; let lhs = self.parse_binops(); - alt self.token { + alt copy self.token { token::EQ { self.bump(); let rhs = self.parse_expr(); @@ -1831,7 +1831,7 @@ class parser { } fn parse_method_name() -> ident { - alt self.token { + alt copy self.token { token::BINOP(op) { self.bump(); token::binop_to_str(op) } token::NOT { self.bump(); "!" } token::LBRACKET { self.bump(); self.expect(token::RBRACKET); "[]" } @@ -2375,7 +2375,7 @@ class parser { while self.token == token::MOD_SEP { self.bump(); - alt self.token { + alt copy self.token { token::IDENT(i, _) { self.bump(); @@ -2477,7 +2477,7 @@ class parser { } fn parse_str() -> str { - alt self.token { + alt copy self.token { token::LIT_STR(s) { self.bump(); self.get_str(s) } _ { self.fatal("expected string literal") diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 882ce7b6461f..329dff0c4c1b 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -59,11 +59,11 @@ type break_t = {offset: int, blank_space: int}; type begin_t = {offset: int, breaks: breaks}; -enum token { STRING(str, int), BREAK(break_t), BEGIN(begin_t), END, EOF, } +enum token { STRING(@str, int), BREAK(break_t), BEGIN(begin_t), END, EOF, } -fn tok_str(t: token) -> str { +fn tok_str(++t: token) -> str { alt t { - STRING(s, len) { ret #fmt["STR(%s,%d)", s, len]; } + STRING(s, len) { ret #fmt["STR(%s,%d)", *s, len]; } BREAK(_) { ret "BREAK"; } BEGIN(_) { ret "BEGIN"; } END { ret "END"; } @@ -109,8 +109,8 @@ fn mk_printer(out: io::writer, linewidth: uint) -> printer { mut space: linewidth as int, mut left: 0u, mut right: 0u, - mut token: token, - mut size: size, + token: token, + size: size, mut left_total: 0, mut right_total: 0, mut scan_stack: scan_stack, @@ -206,8 +206,8 @@ type printer = @{ mut space: int, // number of spaces left on line mut left: uint, // index of left side of input stream mut right: uint, // index of right side of input stream - mut token: [mut token], // ring-buffr stream goes through - mut size: [mut int], // ring-buffer of calculated sizes + token: [mut token], // ring-buffr stream goes through + size: [mut int], // ring-buffer of calculated sizes mut left_total: int, // running size of stream "...left" mut right_total: int, // running size of stream "...right" // pseudo-stack, really a ring too. Holds the @@ -346,7 +346,7 @@ impl printer for printer { self.right %= self.buf_len; assert (self.right != self.left); } - fn advance_left(x: token, L: int) { + fn advance_left(++x: token, L: int) { #debug("advnce_left [%u,%u], sizeof(%u)=%d", self.left, self.right, self.left, L); if L >= 0 { @@ -367,7 +367,7 @@ impl printer for printer { fn check_stack(k: int) { if !self.scan_stack_empty { let x = self.scan_top(); - alt self.token[x] { + alt copy self.token[x] { BEGIN(b) { if k > 0 { self.size[self.scan_pop()] = self.size[x] + @@ -465,7 +465,7 @@ impl printer for printer { assert (L == len); // assert L <= space; self.space -= len; - self.write_str(s); + self.write_str(*s); } EOF { // EOF should never get here. @@ -493,14 +493,14 @@ fn end(p: printer) { p.pretty_print(END); } fn eof(p: printer) { p.pretty_print(EOF); } fn word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, str::len(wrd) as int)); + p.pretty_print(STRING(@wrd, str::len(wrd) as int)); } fn huge_word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, size_infinity)); + p.pretty_print(STRING(@wrd, size_infinity)); } -fn zero_word(p: printer, wrd: str) { p.pretty_print(STRING(wrd, 0)); } +fn zero_word(p: printer, wrd: str) { p.pretty_print(STRING(@wrd, 0)); } fn spaces(p: printer, n: uint) { break_offset(p, n, 0); } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index dd935533b7fc..a8df8d85092b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1703,7 +1703,7 @@ fn print_comment(s: ps, cmnt: comments::cmnt) { // We need to do at least one, possibly two hardbreaks. let is_semi = alt s.s.last_token() { - pp::STRING(s, _) { s == ";" } + pp::STRING(s, _) { *s == ";" } _ { false } }; if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); } From 0d20717fab410cf1f90938d90ad4153b77b6f8b3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 07:59:02 -0700 Subject: [PATCH 35/53] add some purity annotations in dvec/vec, occasional accessor method --- src/libcore/dvec.rs | 14 +++++++++++- src/libcore/vec.rs | 52 ++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs index c7a31b39ad59..ccaab58553f7 100644 --- a/src/libcore/dvec.rs +++ b/src/libcore/dvec.rs @@ -57,6 +57,11 @@ fn dvec() -> dvec { {mut data: [mut]} } +#[doc = "Creates a new dvec with a single element"] +fn from_elt(+e: A) -> dvec { + {mut data: [mut e]} +} + #[doc = "Creates a new dvec with the contents of a vector"] fn from_vec(+v: [mut A]) -> dvec { {mut data: v} @@ -234,7 +239,9 @@ impl extensions for dvec { self.data[idx] = a; } - #[doc = "Overwrites the contents of the element at `idx` with `a`"] + #[doc = "Overwrites the contents of the element at `idx` with `a`, + growing the vector if necessary. New elements will be initialized + with `initval`"] fn grow_set_elt(idx: uint, initval: A, val: A) { self.swap { |v| let mut v <- v; @@ -242,4 +249,9 @@ impl extensions for dvec { v } } + + #[doc = "Returns the last element, failing if the vector is empty"] + fn last() -> A { + self.get_elt(self.len() - 1u) + } } \ No newline at end of file diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 8247ad5b262a..4cfcd6b7517e 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -211,18 +211,18 @@ fn from_mut(+v: [mut T]) -> [T] unsafe { pure fn head(v: [const T]/&) -> T { v[0] } #[doc = "Returns a vector containing all but the first element of a slice"] -fn tail(v: [const T]/&) -> [T] { +pure fn tail(v: [const T]/&) -> [T] { ret slice(v, 1u, len(v)); } #[doc = "Returns a vector containing all but the first `n` \ elements of a slice"] -fn tailn(v: [const T]/&, n: uint) -> [T] { +pure fn tailn(v: [const T]/&, n: uint) -> [T] { slice(v, n, len(v)) } #[doc = "Returns a vector containing all but the last element of a slice"] -fn init(v: [const T]/&) -> [T] { +pure fn init(v: [const T]/&) -> [T] { assert len(v) != 0u; slice(v, 0u, len(v) - 1u) } @@ -1033,10 +1033,10 @@ pure fn unpack_mut_slice(s: [mut T]/&, impl extensions/& for [const T]/& { #[doc = "Returns true if a vector contains no elements"] #[inline] - fn is_empty() -> bool { is_empty(self) } + pure fn is_empty() -> bool { is_empty(self) } #[doc = "Returns true if a vector contains some elements"] #[inline] - fn is_not_empty() -> bool { is_not_empty(self) } + pure fn is_not_empty() -> bool { is_not_empty(self) } #[doc = "Returns the length of a vector"] #[inline] pure fn len() -> uint { len(self) } @@ -1046,28 +1046,28 @@ impl extensions/& for [const T]/& { impl extensions/& for [const T]/& { #[doc = "Returns the first element of a vector"] #[inline] - fn head() -> T { head(self) } + pure fn head() -> T { head(self) } #[doc = "Returns all but the last elemnt of a vector"] #[inline] - fn init() -> [T] { init(self) } + pure fn init() -> [T] { init(self) } #[doc = " Returns the last element of a `v`, failing if the vector is empty. "] #[inline] - fn last() -> T { last(self) } + pure fn last() -> T { last(self) } #[doc = "Returns a copy of the elements from [`start`..`end`) from `v`."] #[inline] - fn slice(start: uint, end: uint) -> [T] { slice(self, start, end) } + pure fn slice(start: uint, end: uint) -> [T] { slice(self, start, end) } #[doc = "Returns all but the first element of a vector"] #[inline] - fn tail() -> [T] { tail(self) } + pure fn tail() -> [T] { tail(self) } } #[doc = "Extension methods for vectors"] impl extensions/& for [T]/& { #[doc = "Reduce a vector from right to left"] #[inline] - fn foldr(z: U, p: fn(T, U) -> U) -> U { foldr(self, z, p) } + pure fn foldr(z: U, p: fn(T, U) -> U) -> U { foldr(self, z, p) } #[doc = " Iterates over a vector @@ -1075,7 +1075,7 @@ impl extensions/& for [T]/& { the element's value. "] #[inline] - fn iter(f: fn(T)) { iter(self, f) } + pure fn iter(f: fn(T)) { iter(self, f) } #[doc = " Iterates over a vector's elements and indexes @@ -1083,7 +1083,7 @@ impl extensions/& for [T]/& { the element's value and index. "] #[inline] - fn iteri(f: fn(uint, T)) { iteri(self, f) } + pure fn iteri(f: fn(uint, T)) { iteri(self, f) } #[doc = " Find the first index matching some predicate @@ -1092,10 +1092,10 @@ impl extensions/& for [T]/& { elements then none is returned. "] #[inline] - fn position(f: fn(T) -> bool) -> option { position(self, f) } + pure fn position(f: fn(T) -> bool) -> option { position(self, f) } #[doc = "Find the first index containing a matching value"] #[inline] - fn position_elem(x: T) -> option { position_elem(self, x) } + pure fn position_elem(x: T) -> option { position_elem(self, x) } #[doc = " Iterates over a vector in reverse @@ -1103,7 +1103,7 @@ impl extensions/& for [T]/& { the element's value. "] #[inline] - fn riter(f: fn(T)) { riter(self, f) } + pure fn riter(f: fn(T)) { riter(self, f) } #[doc =" Iterates over a vector's elements and indexes in reverse @@ -1111,7 +1111,7 @@ impl extensions/& for [T]/& { the element's value and index. "] #[inline] - fn riteri(f: fn(uint, T)) { riteri(self, f) } + pure fn riteri(f: fn(uint, T)) { riteri(self, f) } #[doc = " Find the last index matching some predicate @@ -1120,20 +1120,20 @@ impl extensions/& for [T]/& { matches no elements then none is returned. "] #[inline] - fn rposition(f: fn(T) -> bool) -> option { rposition(self, f) } + pure fn rposition(f: fn(T) -> bool) -> option { rposition(self, f) } #[doc = "Find the last index containing a matching value"] #[inline] - fn rposition_elem(x: T) -> option { rposition_elem(self, x) } + pure fn rposition_elem(x: T) -> option { rposition_elem(self, x) } #[doc = " Apply a function to each element of a vector and return the results "] #[inline] - fn map(f: fn(T) -> U) -> [U] { map(self, f) } + pure fn map(f: fn(T) -> U) -> [U] { map(self, f) } #[doc = " Apply a function to the index and value of each element in the vector and return the results "] - fn mapi(f: fn(uint, T) -> U) -> [U] { + pure fn mapi(f: fn(uint, T) -> U) -> [U] { mapi(self, f) } #[doc = "Returns true if the function returns true for all elements. @@ -1147,7 +1147,7 @@ impl extensions/& for [T]/& { of each result vector "] #[inline] - fn flat_map(f: fn(T) -> [U]) -> [U] { flat_map(self, f) } + pure fn flat_map(f: fn(T) -> [U]) -> [U] { flat_map(self, f) } #[doc = " Apply a function to each element of a vector and return the results @@ -1155,7 +1155,7 @@ impl extensions/& for [T]/& { the resulting vector. "] #[inline] - fn filter_map(f: fn(T) -> option) -> [U] { + pure fn filter_map(f: fn(T) -> option) -> [U] { filter_map(self, f) } } @@ -1170,7 +1170,7 @@ impl extensions/& for [T]/& { only those elements for which `f` returned true. "] #[inline] - fn filter(f: fn(T) -> bool) -> [T] { filter(self, f) } + pure fn filter(f: fn(T) -> bool) -> [T] { filter(self, f) } #[doc = " Search for the first element that matches a given predicate @@ -1179,7 +1179,7 @@ impl extensions/& for [T]/& { is returned. If `f` matches no elements then none is returned. "] #[inline] - fn find(f: fn(T) -> bool) -> option { find(self, f) } + pure fn find(f: fn(T) -> bool) -> option { find(self, f) } #[doc = " Search for the last element that matches a given predicate @@ -1188,7 +1188,7 @@ impl extensions/& for [T]/& { matches no elements then none is returned. "] #[inline] - fn rfind(f: fn(T) -> bool) -> option { rfind(self, f) } + pure fn rfind(f: fn(T) -> bool) -> option { rfind(self, f) } } #[doc = "Unsafe operations"] From 2adb3a5013c2a2d1fdbb27c0fb07a07aa2b83171 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:01:28 -0700 Subject: [PATCH 36/53] add pure annotations in ast_util --- src/libsyntax/ast_util.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 76feba3954c7..cc4593d4af86 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -21,17 +21,17 @@ pure fn mk_sp(lo: uint, hi: uint) -> span { // make this a const, once the compiler supports it pure fn dummy_sp() -> span { ret mk_sp(0u, 0u); } -fn path_name(p: @path) -> str { path_name_i(p.idents) } +pure fn path_name(p: @path) -> str { path_name_i(p.idents) } -fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") } +pure fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") } -fn path_to_ident(p: @path) -> ident { vec::last(p.idents) } +pure fn path_to_ident(p: @path) -> ident { vec::last(p.idents) } -fn local_def(id: node_id) -> def_id { {crate: local_crate, node: id} } +pure fn local_def(id: node_id) -> def_id { {crate: local_crate, node: id} } pure fn is_local(did: ast::def_id) -> bool { did.crate == local_crate } -fn stmt_id(s: stmt) -> node_id { +pure fn stmt_id(s: stmt) -> node_id { alt s.node { stmt_decl(_, id) { id } stmt_expr(_, id) { id } @@ -45,7 +45,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} { _ { fail "non-variant in variant_def_ids"; } } } -fn def_id_of_def(d: def) -> def_id { +pure fn def_id_of_def(d: def) -> def_id { alt d { def_fn(id, _) | def_mod(id) | def_native_mod(id) | def_const(id) | @@ -60,7 +60,7 @@ fn def_id_of_def(d: def) -> def_id { } } -fn binop_to_str(op: binop) -> str { +pure fn binop_to_str(op: binop) -> str { alt op { add { ret "+"; } subtract { ret "-"; } @@ -95,7 +95,7 @@ pure fn is_shift_binop(b: binop) -> bool { } } -fn unop_to_str(op: unop) -> str { +pure fn unop_to_str(op: unop) -> str { alt op { box(mt) { if mt == m_mutbl { ret "@mut "; } ret "@"; } uniq(mt) { if mt == m_mutbl { ret "~mut "; } ret "~"; } @@ -105,11 +105,11 @@ fn unop_to_str(op: unop) -> str { } } -fn is_path(e: @expr) -> bool { +pure fn is_path(e: @expr) -> bool { ret alt e.node { expr_path(_) { true } _ { false } }; } -fn int_ty_to_str(t: int_ty) -> str { +pure fn int_ty_to_str(t: int_ty) -> str { alt t { ty_char { "u8" } // ??? ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" } @@ -117,7 +117,7 @@ fn int_ty_to_str(t: int_ty) -> str { } } -fn int_ty_max(t: int_ty) -> u64 { +pure fn int_ty_max(t: int_ty) -> u64 { alt t { ty_i8 { 0x80u64 } ty_i16 { 0x8000u64 } @@ -126,14 +126,14 @@ fn int_ty_max(t: int_ty) -> u64 { } } -fn uint_ty_to_str(t: uint_ty) -> str { +pure fn uint_ty_to_str(t: uint_ty) -> str { alt t { ty_u { "u" } ty_u8 { "u8" } ty_u16 { "u16" } ty_u32 { "u32" } ty_u64 { "u64" } } } -fn uint_ty_max(t: uint_ty) -> u64 { +pure fn uint_ty_max(t: uint_ty) -> u64 { alt t { ty_u8 { 0xffu64 } ty_u16 { 0xffffu64 } @@ -142,7 +142,7 @@ fn uint_ty_max(t: uint_ty) -> u64 { } } -fn float_ty_to_str(t: float_ty) -> str { +pure fn float_ty_to_str(t: float_ty) -> str { alt t { ty_f { "" } ty_f32 { "f32" } ty_f64 { "f64" } } } From 22cf4b9ac381db02c0db4f81b205f671af844aa5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:02:30 -0700 Subject: [PATCH 37/53] move test to dvec --- src/rustc/front/test.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs index b410cb75ad6f..2cb144a60b5c 100644 --- a/src/rustc/front/test.rs +++ b/src/rustc/front/test.rs @@ -9,6 +9,7 @@ import syntax::codemap::span; import driver::session; import session::session; import syntax::attr; +import dvec::{dvec, extensions}; export modify_for_testing; @@ -20,7 +21,7 @@ type test_ctxt = @{sess: session::session, crate: @ast::crate, mut path: [ast::ident], - mut testfns: [test]}; + testfns: dvec}; // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness @@ -40,7 +41,7 @@ fn generate_test_harness(sess: session::session, @{sess: sess, crate: crate, mut path: [], - mut testfns: []}; + testfns: dvec()}; let precursor = @{fold_crate: fold::wrap(bind fold_crate(cx, _, _)), @@ -110,8 +111,8 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> let test = {span: i.span, path: cx.path, ignore: is_ignored(cx, i), should_fail: should_fail(i)}; - cx.testfns += [test]; - #debug("have %u test functions", vec::len(cx.testfns)); + cx.testfns.push(test); + #debug("have %u test functions", cx.testfns.len()); } } } @@ -269,11 +270,10 @@ fn mk_test_desc_vec_ty(cx: test_ctxt) -> @ast::ty { } fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr { - #debug("building test vector from %u tests", vec::len(cx.testfns)); + #debug("building test vector from %u tests", cx.testfns.len()); let mut descs = []; for cx.testfns.each {|test| - let test_ = test; // Satisfy alias analysis - descs += [mk_test_desc_rec(cx, test_)]; + descs += [mk_test_desc_rec(cx, test)]; } ret @{id: cx.sess.next_node_id(), From 4490c99b113a572d771a3b9171cb83b42813c97c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:02:46 -0700 Subject: [PATCH 38/53] avoid unnecessary by-mut-ref in cargo --- src/cargo/cargo.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs index eee76f24ec2c..ff099f3d007a 100644 --- a/src/cargo/cargo.rs +++ b/src/cargo/cargo.rs @@ -332,7 +332,7 @@ fn try_parse_sources(filename: str, sources: map::hashmap) { } } -fn load_one_source_package(&src: source, p: map::hashmap) { +fn load_one_source_package(&&src: source, p: map::hashmap) { let name = alt p.find("name") { some(json::string(_n)) { _n } _ { @@ -404,8 +404,8 @@ fn load_one_source_package(&src: source, p: map::hashmap) { log(debug, " loaded package: " + src.name + "/" + name); } -fn load_source_packages(&c: cargo, &src: source) { - log(debug, "loading source: " + src.name); +fn load_source_packages(&&c: cargo, &&src: source) { + log(debug, "Loading source: " + src.name); let dir = path::connect(c.sourcedir, src.name); let pkgfile = path::connect(dir, "packages.json"); if !os::path_exists(pkgfile) { ret; } From d9db4f02a4092009a29fa4b2f0be0438856aeb36 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:03:14 -0700 Subject: [PATCH 39/53] move to dvec in metadata --- src/rustc/metadata/creader.rs | 29 ++++++++++++++++------------- src/rustc/metadata/cstore.rs | 4 +++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index 2aacd87cbe85..3356e8cdd652 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -13,6 +13,7 @@ import std::map::{hashmap, int_hash}; import syntax::print::pprust; import filesearch::filesearch; import common::*; +import dvec::{dvec, extensions}; export read_crates; @@ -26,7 +27,7 @@ fn read_crates(diag: span_handler, crate: ast::crate, cstore: cstore, os: os, static: static, - mut crate_cache: [], + crate_cache: dvec(), mut next_crate_num: 1}; let v = visit::mk_simple_visitor(@{visit_view_item: @@ -35,7 +36,7 @@ fn read_crates(diag: span_handler, crate: ast::crate, with *visit::default_simple_visitor()}); visit::visit_crate(crate, (), v); dump_crates(e.crate_cache); - warn_if_multiple_versions(diag, copy e.crate_cache); + warn_if_multiple_versions(diag, e.crate_cache.get()); } type cache_entry = { @@ -45,7 +46,7 @@ type cache_entry = { metas: @[@ast::meta_item] }; -fn dump_crates(crate_cache: [cache_entry]) { +fn dump_crates(crate_cache: dvec) { #debug("resolved crates:"); for crate_cache.each {|entry| #debug("cnum: %?", entry.cnum); @@ -64,10 +65,10 @@ fn warn_if_multiple_versions(diag: span_handler, crate_cache: [cache_entry]) { import either::*; - if crate_cache.is_not_empty() { + if crate_cache.len() != 0u { let name = loader::crate_name_from_metas(*crate_cache.last().metas); let {lefts: matches, rights: non_matches} = - partition(crate_cache.map {|entry| + partition(crate_cache.map_to_vec {|entry| let othername = loader::crate_name_from_metas(*entry.metas); if name == othername { left(entry) @@ -99,7 +100,7 @@ type env = @{diag: span_handler, cstore: cstore::cstore, os: loader::os, static: bool, - mut crate_cache: [cache_entry], + crate_cache: dvec, mut next_crate_num: ast::crate_num}; fn visit_view_item(e: env, i: @ast::view_item) { @@ -176,12 +177,14 @@ fn metas_with_ident(ident: ast::ident, fn existing_match(e: env, metas: [@ast::meta_item], hash: str) -> option { - let maybe_entry = e.crate_cache.find {|c| - loader::metadata_matches(*c.metas, metas) && - (hash.is_empty() || c.hash == hash) - }; - maybe_entry.map {|c| c.cnum } + for e.crate_cache.each {|c| + if loader::metadata_matches(*c.metas, metas) + && (hash.is_empty() || c.hash == hash) { + ret some(c.cnum); + } + } + ret none; } fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item], @@ -211,8 +214,8 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item], // Claim this crate number and cache it let cnum = e.next_crate_num; - e.crate_cache += [{cnum: cnum, span: span, - hash: hash, metas: @linkage_metas}]; + e.crate_cache.push({cnum: cnum, span: span, + hash: hash, metas: @linkage_metas}); e.next_crate_num += 1; // Now resolve the crates referenced by this crate diff --git a/src/rustc/metadata/cstore.rs b/src/rustc/metadata/cstore.rs index 22d19f81c868..0bbbeafdb54a 100644 --- a/src/rustc/metadata/cstore.rs +++ b/src/rustc/metadata/cstore.rs @@ -63,7 +63,9 @@ type cstore_private = type use_crate_map = map::hashmap; // Internal method to retrieve the data from the cstore -fn p(cstore: cstore) -> cstore_private { alt cstore { private(p) { p } } } +pure fn p(cstore: cstore) -> cstore_private { + alt cstore { private(p) { p } } +} fn mk_cstore() -> cstore { let meta_cache = map::int_hash::(); From 08520a16978264eb599d4df843794126656f78d3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:03:33 -0700 Subject: [PATCH 40/53] move borrowck to dvec, insert a few minor copies --- src/rustc/middle/borrowck.rs | 3 ++- src/rustc/middle/borrowck/check_loans.rs | 18 ++++++++++-------- src/rustc/middle/borrowck/gather_loans.rs | 7 ++++--- src/rustc/middle/borrowck/loan.rs | 12 ++++++------ 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index 2b52cd675a66..d106c2b23d86 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -164,6 +164,7 @@ import util::common::indenter; import ast_util::op_expr_callee_id; import ty::to_str; import driver::session::session; +import dvec::{dvec, extensions}; export check_crate, root_map, mutbl_map; @@ -298,7 +299,7 @@ type loan = {lp: @loan_path, cmt: cmt, mutbl: ast::mutability}; // maps computed by `gather_loans` that are then used by `check_loans` type req_maps = { - req_loan_map: hashmap, + req_loan_map: hashmap>>, pure_map: hashmap }; diff --git a/src/rustc/middle/borrowck/check_loans.rs b/src/rustc/middle/borrowck/check_loans.rs index 615a6737c834..04a37d327cda 100644 --- a/src/rustc/middle/borrowck/check_loans.rs +++ b/src/rustc/middle/borrowck/check_loans.rs @@ -7,6 +7,7 @@ // 3. assignments do not affect things loaned out as immutable // 4. moves to dnot affect things loaned out in any way +import dvec::{dvec, extensions}; import categorization::public_methods; export check_loans; @@ -22,7 +23,7 @@ enum check_loan_ctxt = @{ // we are in a ctor, we track the self id mut in_ctor: bool, mut declared_purity: ast::purity, - mut fn_args: [ast::node_id] + mut fn_args: @[ast::node_id] }; // if we are enforcing purity, why are we doing so? @@ -44,7 +45,7 @@ fn check_loans(bccx: borrowck_ctxt, reported: int_hash(), mut in_ctor: false, mut declared_purity: ast::impure_fn, - mut fn_args: []}); + mut fn_args: @[]}); let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr, visit_block: check_loans_in_block, visit_fn: check_loans_in_fn @@ -179,7 +180,7 @@ impl methods for check_loan_ctxt { let did = ast_util::def_id_of_def(def); let is_fn_arg = did.crate == ast::local_crate && - self.fn_args.contains(did.node); + (*self.fn_args).contains(did.node); if is_fn_arg { ret; } // case (a) above } ast::expr_fn_block(*) | ast::expr_fn(*) | @@ -225,7 +226,8 @@ impl methods for check_loan_ctxt { ast::expr_path(_) { let def = self.tcx().def_map.get(expr.id); let did = ast_util::def_id_of_def(def); - did.crate == ast::local_crate && self.fn_args.contains(did.node) + did.crate == ast::local_crate && + (*self.fn_args).contains(did.node) } ast::expr_fn_block(*) | ast::expr_fn(*) { self.is_stack_closure(expr.id) @@ -484,7 +486,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]; + #debug["purity on entry=%?", copy self.declared_purity]; save_and_restore(self.in_ctor) {|| save_and_restore(self.declared_purity) {|| save_and_restore(self.fn_args) {|| @@ -500,7 +502,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, visit::fk_ctor(*) { self.in_ctor = true; self.declared_purity = decl.purity; - self.fn_args = decl.inputs.map({|i| i.id}); + self.fn_args = @decl.inputs.map({|i| i.id}); } visit::fk_anon(*) | visit::fk_fn_block(*) if is_stack_closure { @@ -512,7 +514,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, visit::fk_res(*) | visit::fk_dtor(*) { self.in_ctor = false; self.declared_purity = decl.purity; - self.fn_args = decl.inputs.map({|i| i.id}); + self.fn_args = @decl.inputs.map({|i| i.id}); } } @@ -520,7 +522,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, } } } - #debug["purity on exit=%?", self.declared_purity]; + #debug["purity on exit=%?", copy self.declared_purity]; } fn check_loans_in_expr(expr: @ast::expr, diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index 373488e55470..fe59d771042f 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -273,13 +273,14 @@ impl methods for gather_loan_ctxt { } } - fn add_loans(scope_id: ast::node_id, loans: @const [loan]) { + fn add_loans(scope_id: ast::node_id, loans: @dvec) { alt self.req_maps.req_loan_map.find(scope_id) { some(l) { - *l += [loans]; + (*l).push(loans); } none { - self.req_maps.req_loan_map.insert(scope_id, @mut [loans]); + self.req_maps.req_loan_map.insert( + scope_id, @dvec::from_vec([mut loans])); } } } diff --git a/src/rustc/middle/borrowck/loan.rs b/src/rustc/middle/borrowck/loan.rs index e54ac388f0f3..c0e6f4accf70 100644 --- a/src/rustc/middle/borrowck/loan.rs +++ b/src/rustc/middle/borrowck/loan.rs @@ -5,8 +5,8 @@ export public_methods; impl public_methods for borrowck_ctxt { - fn loan(cmt: cmt, mutbl: ast::mutability) -> @const [loan] { - let lc = @{bccx: self, loans: @mut []}; + fn loan(cmt: cmt, mutbl: ast::mutability) -> @dvec { + let lc = @{bccx: self, loans: @dvec()}; lc.loan(cmt, mutbl); ret lc.loans; } @@ -14,7 +14,7 @@ impl public_methods for borrowck_ctxt { type loan_ctxt = @{ bccx: borrowck_ctxt, - loans: @mut [loan] + loans: @dvec }; impl loan_methods for loan_ctxt { @@ -23,9 +23,9 @@ impl loan_methods for loan_ctxt { // Note: all cmt's that we deal with will have a non-none lp, because // the entry point into this routine, `borrowck_ctxt::loan()`, rejects // any cmt with a none-lp. - *self.loans += [{lp:option::get(cmt.lp), - cmt:cmt, - mutbl:mutbl}]; + (*self.loans).push({lp:option::get(cmt.lp), + cmt:cmt, + mutbl:mutbl}); } fn loan(cmt: cmt, req_mutbl: ast::mutability) { From 7d17c2d87ff738aa2f4895255f99e2e89112cbb6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:04:43 -0700 Subject: [PATCH 41/53] move check_const to dvec --- src/rustc/middle/check_const.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/rustc/middle/check_const.rs b/src/rustc/middle/check_const.rs index 4fbab3879d0c..6c2032c9c34d 100644 --- a/src/rustc/middle/check_const.rs +++ b/src/rustc/middle/check_const.rs @@ -2,6 +2,7 @@ import syntax::ast::*; import syntax::{visit, ast_util, ast_map}; import driver::session::session; import std::map::hashmap; +import dvec::{dvec, extensions}; fn check_crate(sess: session, crate: @crate, ast_map: ast_map::map, def_map: resolve::def_map, @@ -130,7 +131,7 @@ fn check_item_recursion(sess: session, ast_map: ast_map::map, sess: session, ast_map: ast_map::map, def_map: resolve::def_map, - idstack: @mut [node_id], + idstack: @dvec, }; let env = { @@ -138,7 +139,7 @@ fn check_item_recursion(sess: session, ast_map: ast_map::map, sess: sess, ast_map: ast_map, def_map: def_map, - idstack: @mut [] + idstack: @dvec() }; let visitor = visit::mk_vt(@{ @@ -152,9 +153,9 @@ fn check_item_recursion(sess: session, ast_map: ast_map::map, if (*env.idstack).contains(it.id) { env.sess.span_fatal(env.root_it.span, "recursive constant"); } - vec::push(*env.idstack, it.id); + (*env.idstack).push(it.id); visit::visit_item(it, env, v); - vec::pop(*env.idstack); + (*env.idstack).pop(); } fn visit_expr(e: @expr, &&env: env, v: visit::vt) { From 594e01d007bf83ab90380614653cf8e2a3a4cb99 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:05:29 -0700 Subject: [PATCH 42/53] add pure, copies to liveness --- src/rustc/middle/liveness.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index 3f82e647ab6b..729ffa0bb93b 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -133,7 +133,7 @@ impl of to_str::to_str for variable { // assignment. And so forth. impl methods for live_node { - fn is_valid() -> bool { *self != uint::max_value } + pure fn is_valid() -> bool { *self != uint::max_value } } fn invalid_node() -> live_node { live_node(uint::max_value) } @@ -571,7 +571,7 @@ class liveness { fn live_on_exit(ln: live_node, var: variable) -> option { - self.live_on_entry(self.successors[*ln], var) + self.live_on_entry(copy self.successors[*ln], var) } fn used_on_entry(ln: live_node, var: variable) -> bool { @@ -590,7 +590,7 @@ class liveness { fn assigned_on_exit(ln: live_node, var: variable) -> option { - self.assigned_on_entry(self.successors[*ln], var) + self.assigned_on_entry(copy self.successors[*ln], var) } fn indices(ln: live_node, op: fn(uint)) { @@ -627,14 +627,14 @@ class liveness { wr.write_str("[ln("); wr.write_uint(*ln); wr.write_str(") of kind "); - wr.write_str(#fmt["%?", self.ir.lnks[*ln]]); + wr.write_str(#fmt["%?", copy self.ir.lnks[*ln]]); wr.write_str(" reads"); self.write_vars(wr, ln, {|idx| self.users[idx].reader}); wr.write_str(" writes"); self.write_vars(wr, ln, {|idx| self.users[idx].writer}); wr.write_str(" "); wr.write_str(" precedes "); - wr.write_str(self.successors[*ln].to_str()); + wr.write_str((copy self.successors[*ln]).to_str()); wr.write_str("]"); } } @@ -668,9 +668,9 @@ class liveness { let mut changed = false; self.indices2(ln, succ_ln) { |idx, succ_idx| - changed |= copy_if_invalid(self.users[succ_idx].reader, + changed |= copy_if_invalid(copy self.users[succ_idx].reader, self.users[idx].reader); - changed |= copy_if_invalid(self.users[succ_idx].writer, + changed |= copy_if_invalid(copy self.users[succ_idx].writer, self.users[idx].writer); if self.users[succ_idx].used && !self.users[idx].used { self.users[idx].used = true; From 9be612f7eeb4757fc5be8cb377a9c1e840a231b3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:06:04 -0700 Subject: [PATCH 43/53] move resolve to dvec, remove unnecessary mut annotations --- src/rustc/middle/resolve.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index a92db033c229..6c75e470c0a8 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -100,7 +100,7 @@ type glob_imp_def = {def: def, path: @ast::view_path}; type indexed_mod = { m: option, index: mod_index, - mut glob_imports: [glob_imp_def], + glob_imports: dvec, mut globbed_exports: [ident], glob_imported_names: hashmap, path: str @@ -123,7 +123,7 @@ type env = def_map: def_map, ast_map: ast_map::map, imports: hashmap, - mut exp_map: exp_map, + exp_map: exp_map, mod_map: hashmap, block_map: hashmap, ext_map: ext_map, @@ -132,7 +132,7 @@ type env = ext_cache: ext_hash, used_imports: {mut track: bool, mut data: [node_id]}, - mut reported: [{ident: str, sc: scope}], + reported: dvec<{ident: str, sc: scope}>, mut ignored_imports: [node_id], mut current_tp: option, mut resolve_unexported: bool, @@ -174,7 +174,7 @@ fn create_env(sess: session, amap: ast_map::map) -> @env { def_map: int_hash(), ast_map: amap, imports: int_hash(), - mut exp_map: int_hash(), + exp_map: int_hash(), mod_map: int_hash(), block_map: int_hash(), ext_map: new_def_hash(), @@ -182,7 +182,7 @@ fn create_env(sess: session, amap: ast_map::map) -> @env { impl_cache: new_def_hash(), ext_cache: new_ext_hash(), used_imports: {mut track: false, mut data: []}, - mut reported: [], + reported: dvec(), mut ignored_imports: [], mut current_tp: none, mut resolve_unexported: false, @@ -270,7 +270,7 @@ fn map_crate(e: @env, c: @ast::crate) { e.mod_map.insert(i.id, @{m: some(md), index: index_mod(md), - mut glob_imports: [], + glob_imports: dvec(), mut globbed_exports: [], glob_imported_names: str_hash(), path: path_from_scope(sc, i.ident)}); @@ -279,7 +279,7 @@ fn map_crate(e: @env, c: @ast::crate) { e.mod_map.insert(i.id, @{m: none::, index: index_nmod(nmd), - mut glob_imports: [], + glob_imports: dvec(), mut globbed_exports: [], glob_imported_names: str_hash(), path: path_from_scope(sc, i.ident)}); @@ -301,7 +301,7 @@ fn map_crate(e: @env, c: @ast::crate) { let glob = {def: imp, path: vp}; alt list::head(sc) { scope_item(i) { - e.mod_map.get(i.id).glob_imports += [glob]; + e.mod_map.get(i.id).glob_imports.push(glob); } scope_block(b, _, _) { let globs = alt e.block_map.find(b.node.id) { @@ -311,8 +311,8 @@ fn map_crate(e: @env, c: @ast::crate) { e.block_map.insert(b.node.id, globs); } scope_crate { - e.mod_map.get(ast::crate_node_id).glob_imports - += [glob]; + e.mod_map.get(ast::crate_node_id). + glob_imports.push(glob); } _ { e.sess.span_bug(vi.span, "unexpected scope in a \ glob import"); } @@ -338,7 +338,7 @@ fn map_crate(e: @env, c: @ast::crate) { e.mod_map.insert(ast::crate_node_id, @{m: some(c.node.module), index: index_mod(c.node.module), - mut glob_imports: [], + glob_imports: dvec(), mut globbed_exports: [], glob_imported_names: str_hash(), path: ""}); @@ -899,7 +899,7 @@ fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) { for e.reported.each {|rs| if str::eq(rs.ident, name) && err_scope == rs.sc { ret; } } - e.reported += [{ident: name, sc: err_scope}]; + e.reported.push({ident: name, sc: err_scope}); } _ {} } @@ -1536,7 +1536,7 @@ fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident, // absence takes the place of todo() if !info.glob_imported_names.contains_key(id) { info.glob_imported_names.insert(id, glob_resolving(sp)); - let globs = info.glob_imports; + let globs = info.glob_imports.get(); let val = lookup_in_globs(e, globs, sp, id, ns_val, dr); let typ = lookup_in_globs(e, globs, sp, id, ns_type, dr); let md = lookup_in_globs(e, globs, sp, id, ns_module, dr); From e8dfe179da7ff0c679d6020fe658c8edd076a602 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 08:06:36 -0700 Subject: [PATCH 44/53] move tstate to dvec --- src/rustc/middle/tstate/auxiliary.rs | 44 +++++++++++------------ src/rustc/middle/tstate/collect_locals.rs | 8 ++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index c34953ac33e6..2844aa685950 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -16,6 +16,7 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, import tritv::*; import bitvectors::promises_; import driver::session::session; +import dvec::{dvec, extensions}; import syntax::print::pprust::{constr_args_to_str, lit_to_str}; @@ -197,7 +198,7 @@ type constraint = { path: @path, // FIXME: really only want it to be mut during collect_locals. // freeze it after that. - descs: @mut [pred_args] + descs: @dvec }; type tsconstr = { @@ -473,8 +474,7 @@ fn node_id_to_def(ccx: crate_ctxt, id: node_id) -> option { fn norm_a_constraint(id: def_id, c: constraint) -> [norm_constraint] { let mut rslt: [norm_constraint] = []; - let descs = *c.descs; - for vec::each(descs) {|pd| + for (*c.descs).each {|pd| rslt += [{bit_num: pd.node.bit_num, c: respan(pd.span, {path: c.path, @@ -498,11 +498,11 @@ fn constraints(fcx: fn_ctxt) -> [norm_constraint] { // FIXME // Would rather take an immutable vec as an argument, // should freeze it at some earlier point. -fn match_args(fcx: fn_ctxt, occs: @mut [pred_args], +fn match_args(fcx: fn_ctxt, occs: @dvec, occ: [@constr_arg_use]) -> uint { #debug("match_args: looking at %s", constr_args_to_str(fn@(i: inst) -> str { ret i.ident; }, occ)); - for vec::each(*occs) {|pd| + for (*occs).each {|pd| log(debug, "match_args: candidate " + pred_args_to_str(pd)); fn eq(p: inst, q: inst) -> bool { ret p.node == q.node; } @@ -613,7 +613,8 @@ fn substitute_arg(cx: ty::ctxt, actuals: [@expr], a: @constr_arg) -> } } -fn pred_args_matches(pattern: [constr_arg_general_], desc: pred_args) -> +fn pred_args_matches(pattern: [constr_arg_general_], + desc: pred_args) -> bool { let mut i = 0u; for desc.node.args.each {|c| @@ -638,7 +639,8 @@ fn pred_args_matches(pattern: [constr_arg_general_], desc: pred_args) -> ret true; } -fn find_instance_(pattern: [constr_arg_general_], descs: [pred_args]) -> +fn find_instance_(pattern: [constr_arg_general_], + descs: [pred_args]) -> option { for descs.each {|d| if pred_args_matches(pattern, d) { ret some(d.node.bit_num); } @@ -660,15 +662,19 @@ fn find_instances(_fcx: fn_ctxt, subst: subst, if vec::len(subst) == 0u { ret []; } let mut res = []; - for (*c.descs).each { |d| - if args_mention(d.node.args, find_in_subst_bool, subst) { - let old_bit_num = d.node.bit_num; - let newv = replace(subst, d); - alt find_instance_(newv, *c.descs) { - some(d1) {res += [{from: old_bit_num, to: d1}]} - _ {} - } - } else {} + (*c.descs).swap { |v| + let v <- vec::from_mut(v); + for v.each { |d| + if args_mention(d.node.args, find_in_subst_bool, subst) { + let old_bit_num = d.node.bit_num; + let newv = replace(subst, d); + alt find_instance_(newv, v) { + some(d1) {res += [{from: old_bit_num, to: d1}]} + _ {} + } + } else {} + } + vec::to_mut(v) } ret res; } @@ -897,12 +903,6 @@ fn args_mention(args: [@constr_arg_use], fn use_var(fcx: fn_ctxt, v: node_id) { *fcx.enclosing.used_vars += [v]; } -// FIXME: This should be a function in vec::. -fn vec_contains(v: @mut [node_id], i: node_id) -> bool { - for vec::each(*v) {|d| if d == i { ret true; } } - ret false; -} - fn op_to_oper_ty(io: init_op) -> oper_type { alt io { init_move { oper_move } _ { oper_assign } } } diff --git a/src/rustc/middle/tstate/collect_locals.rs b/src/rustc/middle/tstate/collect_locals.rs index f8575569c5ac..0d3ab5321df3 100644 --- a/src/rustc/middle/tstate/collect_locals.rs +++ b/src/rustc/middle/tstate/collect_locals.rs @@ -8,6 +8,7 @@ import syntax::ast_util::respan; import driver::session::session; import aux::*; import std::map::hashmap; +import dvec::{dvec, extensions}; type ctxt = {cs: @mut [sp_constr], tcx: ty::ctxt}; @@ -57,12 +58,11 @@ fn add_constraint(tcx: ty::ctxt, c: sp_constr, next: uint, tbl: constr_map) -> let {path: p, def_id: d_id, args: args} = c.node; alt tbl.find(d_id) { some(ct) { - let {path: _, descs: pds} = ct; - *pds += [respan(c.span, {args: args, bit_num: next})]; + (*ct.descs).push(respan(c.span, {args: args, bit_num: next})); } none { - let rslt: @mut [pred_args] = - @mut [respan(c.span, {args: args, bit_num: next})]; + let rslt = @dvec(); + (*rslt).push(respan(c.span, {args: args, bit_num: next})); tbl.insert(d_id, {path:p, descs:rslt}); } } From 8ebbf464f59f3a400de91d7afac0c254e3346c72 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 10:44:19 -0700 Subject: [PATCH 45/53] minor changes to tests so they pass borrowck --- src/test/auxiliary/cci_nested_lib.rs | 18 +++++++++--------- src/test/compile-fail/issue-511.rs | 2 ++ src/test/run-pass/alt-pattern-drop.rs | 4 +++- .../class-implements-multiple-ifaces.rs | 11 ++++++----- src/test/run-pass/iface-cast.rs | 7 +++---- src/test/run-pass/maybe-mutable.rs | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/test/auxiliary/cci_nested_lib.rs b/src/test/auxiliary/cci_nested_lib.rs index 9c26221960ca..87ab9bbcfea3 100644 --- a/src/test/auxiliary/cci_nested_lib.rs +++ b/src/test/auxiliary/cci_nested_lib.rs @@ -1,14 +1,16 @@ -type alist = { eq_fn: fn@(A,A) -> bool, mut data: [(A,B)] }; +import dvec::{dvec,extensions}; + +type entry = {key: A, value: B}; +type alist = { eq_fn: fn@(A,A) -> bool, data: dvec> }; fn alist_add(lst: alist, k: A, v: B) { - lst.data += [(k, v)]; + lst.data.push({key:k, value:v}); } fn alist_get(lst: alist, k: A) -> B { let eq_fn = lst.eq_fn; - for lst.data.each {|pair| - let (ki, vi) = pair; // copy req'd for alias analysis - if eq_fn(k, ki) { ret vi; } + for lst.data.each {|entry| + if eq_fn(entry.key, k) { ret entry.value; } } fail; } @@ -16,14 +18,12 @@ fn alist_get(lst: alist, k: A) -> B { #[inline] fn new_int_alist() -> alist { fn eq_int(&&a: int, &&b: int) -> bool { a == b } - ret {eq_fn: eq_int, - mut data: []}; + ret {eq_fn: eq_int, data: dvec()}; } #[inline] fn new_int_alist_2() -> alist { #[inline] fn eq_int(&&a: int, &&b: int) -> bool { a == b } - ret {eq_fn: eq_int, - mut data: []}; + ret {eq_fn: eq_int, data: dvec()}; } \ No newline at end of file diff --git a/src/test/compile-fail/issue-511.rs b/src/test/compile-fail/issue-511.rs index f2ef8c90c3f6..793bb48c79a7 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/compile-fail/issue-511.rs @@ -8,4 +8,6 @@ fn f(&o: option) { fn main() { f::(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 } \ No newline at end of file diff --git a/src/test/run-pass/alt-pattern-drop.rs b/src/test/run-pass/alt-pattern-drop.rs index 81ea2a2d7749..0af65bd18270 100644 --- a/src/test/run-pass/alt-pattern-drop.rs +++ b/src/test/run-pass/alt-pattern-drop.rs @@ -25,8 +25,10 @@ fn foo(s: @int) { fn main() { let s: @int = @0; // ref up + let count = dbg::refcount(s); + foo(s); // ref up then down log(debug, dbg::refcount(s)); - assert (dbg::refcount(s) == 1u); + assert (dbg::refcount(s) == count); } diff --git a/src/test/run-pass/class-implements-multiple-ifaces.rs b/src/test/run-pass/class-implements-multiple-ifaces.rs index 44cd125e1963..1a8f77776720 100644 --- a/src/test/run-pass/class-implements-multiple-ifaces.rs +++ b/src/test/run-pass/class-implements-multiple-ifaces.rs @@ -1,6 +1,7 @@ use std; import std::map::*; import vec::*; +import dvec::{dvec, extensions}; enum furniture { chair, couch, bed } enum body_part { finger, toe, nose, ear } @@ -26,7 +27,7 @@ fn vec_includes(xs: [T], x: T) -> bool { class cat implements noisy, scratchy, bitey { priv { let meows : @mut uint; - let scratched : @mut [furniture]; + let scratched : dvec; let bite_counts : hashmap; fn meow() -> uint { @@ -44,7 +45,7 @@ class cat implements noisy, scratchy, bitey { new(in_x : uint, in_y : int, in_name: str) { self.meows = @mut in_x; self.how_hungry = @mut in_y; - self.name = in_name; self.scratched = @mut []; + self.name = in_name; self.scratched = dvec(); let hsher: hashfn = fn@(p: body_part) -> uint { int::hash(p as int) }; let eqer : eqfn = @@ -61,10 +62,10 @@ class cat implements noisy, scratchy, bitey { fn meow_count() -> uint { *self.meows } fn scratch() -> option { let all = [chair, couch, bed]; - log(error, *(self.scratched)); + log(error, self.scratched); let mut rslt = none; - for each(all) {|thing| if !vec_includes(*(self.scratched), thing) { - *self.scratched += [thing]; + for each(all) {|thing| if !self.scratched.contains(thing) { + self.scratched.push(thing); ret some(thing); }} rslt } diff --git a/src/test/run-pass/iface-cast.rs b/src/test/run-pass/iface-cast.rs index b771eca4be80..1377bb2a2790 100644 --- a/src/test/run-pass/iface-cast.rs +++ b/src/test/run-pass/iface-cast.rs @@ -26,10 +26,9 @@ impl of to_str for int { impl of to_str for Tree { fn to_str() -> str { - #fmt["[%s, %s, %s]", - self.val.to_str(), - self.left.to_str(), - self.right.to_str()] + let l = self.left, r = self.right; + #fmt["[%s, %s, %s]", self.val.to_str(), + l.to_str(), r.to_str()] } } diff --git a/src/test/run-pass/maybe-mutable.rs b/src/test/run-pass/maybe-mutable.rs index 8c9d63922a6f..4f305ff83788 100644 --- a/src/test/run-pass/maybe-mutable.rs +++ b/src/test/run-pass/maybe-mutable.rs @@ -4,7 +4,7 @@ // -*- rust -*- fn len(v: [const int]) -> uint { let mut i = 0u; - for v.each {|x| i += 1u; } + while i < vec::len(v) { i += 1u; } ret i; } From dd37c0a41e3c695886fb2f3c33f7fee6675822aa Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Jun 2012 12:31:25 -0700 Subject: [PATCH 46/53] mask extra borrowck errors (should find out how to not report those) --- src/test/compile-fail/issue-511.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/issue-511.rs b/src/test/compile-fail/issue-511.rs index 793bb48c79a7..40d25a375668 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/compile-fail/issue-511.rs @@ -8,6 +8,8 @@ fn f(&o: option) { fn main() { f::(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 From ab8fa495d08f64c5a82bc8ed39f9e2066aec4b6b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 Jun 2012 16:01:14 -0700 Subject: [PATCH 47/53] some (very little) work on commenting --- src/rustc/middle/borrowck/categorization.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index c7103b6899c4..ff9d51196c91 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -7,7 +7,15 @@ determine what kind of memory is used in evaluating it (for example, where dereferences occur and what kind of pointer is dereferenced; whether the memory is mutable; etc) +Categorization effectively transforms all of our expressions into +expressions of the following forms (the actual enum has many more +possibilities, naturally, but they are all variants of these base +forms): + E = rvalue // some computed rvalue + | x // address of a local variable, arg, or upvar + | *E // deref of a ptr + | E.comp // access to an interior component Imagine a routine ToAddr(Expr) that evaluates an expression and returns an address where the result is to be found. If Expr is an lvalue, then this From 9c1910a66db95468608c9cc02a5012e3db7f4e09 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 Jun 2012 16:01:00 -0700 Subject: [PATCH 48/53] workaround LLVM bug #13042 --- src/libsyntax/parse/common.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 05e14c4654df..35afb79ce63f 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -94,8 +94,11 @@ impl parser_common for parser { fn eat_keyword(word: str) -> bool { self.require_keyword(word); - alt copy self.token { - token::IDENT(sid, false) { + + // FIXME: this gratuitous use of @ is to + // workaround LLVM bug #13042 + alt @self.token { + @token::IDENT(sid, false) { if str::eq(word, self.get_str(sid)) { self.bump(); ret true; From f4fb0f9eea00c619c2b91f83072306e89549c260 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 19:20:38 -0700 Subject: [PATCH 49/53] Handle regions correctly in class ctors and dtors Class ctors and dtors were always getting assigned the empty region before, which meant a reference to the "self" region in a ctor argument got resolved to a named region called "self" rather than the class's self region, which led to a rather confusing error message as documented in #2502. Closes #2502 --- src/rustc/middle/typeck/collect.rs | 20 ++++++-------------- src/test/run-pass/issue-2502.rs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/issue-2502.rs diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index e97629a823b6..e81bd9d35478 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -369,31 +369,23 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { let t_ctor = ty::mk_fn( tcx, - ty_of_fn_decl(ccx, - empty_rscope, - ast::proto_any, - ctor.node.dec, - none)); + ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_any, + ctor.node.dec, none)); write_ty_to_tcx(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, - rp: ast::rp_none, + rp: rp, ty: t_ctor}); option::iter(m_dtor) {|dtor| // Write the dtor type let t_dtor = ty::mk_fn( tcx, - // not sure about empty_rscope - // FIXME - ty_of_fn_decl(ccx, - empty_rscope, - ast::proto_any, - ast_util::dtor_dec(), - none)); + ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_any, + ast_util::dtor_dec(), none)); write_ty_to_tcx(tcx, dtor.node.id, t_dtor); tcx.tcache.insert(local_def(dtor.node.id), {bounds: tpt.bounds, - rp: ast::rp_none, + rp: rp, ty: t_dtor}); }; ensure_iface_methods(ccx, it.id); diff --git a/src/test/run-pass/issue-2502.rs b/src/test/run-pass/issue-2502.rs new file mode 100644 index 000000000000..6aa35169dd5c --- /dev/null +++ b/src/test/run-pass/issue-2502.rs @@ -0,0 +1,13 @@ +class font/& { + let fontbuf: &self.[u8]; + + new(fontbuf: &self.[u8]) { + self.fontbuf = fontbuf; + } + + fn buf() -> &self.[u8] { + self.fontbuf + } +} + +fn main() { } From 3251bd690eadc41f4163bdb11975b15ff739fa47 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Jun 2012 19:38:47 -0700 Subject: [PATCH 50/53] Fix some copy-paste bugs in visit glue, un-xfail reflect-visit-type. --- src/rustc/middle/trans/base.rs | 4 ++- src/rustc/middle/trans/reflect.rs | 41 +++++++++++++------------ src/test/run-pass/reflect-visit-type.rs | 4 --- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index ff297c5dcd48..c1d05bf39da1 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -1186,7 +1186,7 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint, } } } else if field == abi::tydesc_field_visit_glue { - alt ti.free_glue { + alt ti.visit_glue { some(_) { } none { #debug("+++ lazily_emit_tydesc_glue VISIT %s", @@ -1222,6 +1222,8 @@ fn call_tydesc_glue_full(cx: block, v: ValueRef, tydesc: ValueRef, static_glue_fn = sti.drop_glue; } else if field == abi::tydesc_field_free_glue { static_glue_fn = sti.free_glue; + } else if field == abi::tydesc_field_visit_glue { + static_glue_fn = sti.visit_glue; } } } diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs index 336cb897ed3b..09c5ebbf96aa 100644 --- a/src/rustc/middle/trans/reflect.rs +++ b/src/rustc/middle/trans/reflect.rs @@ -24,29 +24,30 @@ fn visit_ty_steps(bcx: block, t: ty::t, ty::ty_bool { step(bcx, "visit_bool", []) } ty::ty_int(ast::ty_i) { step(bcx, "visit_int", []) } ty::ty_int(ast::ty_char) { step(bcx, "visit_char", []) } - ty::ty_int(ast::ty_i8) { step(bcx, "visit_i8", []) } - ty::ty_int(ast::ty_i16) { step(bcx, "visit_i16", []) } - ty::ty_int(ast::ty_i32) { step(bcx, "visit_i32", []) } - ty::ty_int(ast::ty_i64) { step(bcx, "visit_i64", []) } - ty::ty_uint(ast::ty_u) { step(bcx, "visit_uint", []) } - ty::ty_uint(ast::ty_u8) { step(bcx, "visit_u8", []) } - ty::ty_uint(ast::ty_u16) { step(bcx, "visit_u16", []) } - ty::ty_uint(ast::ty_u32) { step(bcx, "visit_u32", []) } - ty::ty_uint(ast::ty_u64) { step(bcx, "visit_u64", []) } - ty::ty_float(ast::ty_f) { step(bcx, "visit_float", []) } - ty::ty_float(ast::ty_f32) { step(bcx, "visit_f32", []) } - ty::ty_float(ast::ty_f64) { step(bcx, "visit_f64", []) } - ty::ty_str { step(bcx, "visit_str", []) } + ty::ty_int(ast::ty_i8) { step(bcx, "visit_i8", []) } + ty::ty_int(ast::ty_i16) { step(bcx, "visit_i16", []) } + ty::ty_int(ast::ty_i32) { step(bcx, "visit_i32", []) } + ty::ty_int(ast::ty_i64) { step(bcx, "visit_i64", []) } + ty::ty_uint(ast::ty_u) { step(bcx, "visit_uint", []) } + ty::ty_uint(ast::ty_u8) { step(bcx, "visit_u8", []) } + ty::ty_uint(ast::ty_u16) { step(bcx, "visit_u16", []) } + ty::ty_uint(ast::ty_u32) { step(bcx, "visit_u32", []) } + ty::ty_uint(ast::ty_u64) { step(bcx, "visit_u64", []) } + ty::ty_float(ast::ty_f) { step(bcx, "visit_float", []) } + ty::ty_float(ast::ty_f32) { step(bcx, "visit_f32", []) } + ty::ty_float(ast::ty_f64) { step(bcx, "visit_f64", []) } + ty::ty_str { step(bcx, "visit_str", []) } - ty::ty_vec(mt) { - let bcx = step(bcx, "visit_vec_of", - [C_uint(ccx, mt.mutbl as uint)]); - sub(bcx, mt.ty) - } + ty::ty_vec(mt) { + let bcx = step(bcx, "visit_vec_of", + [C_uint(ccx, mt.mutbl as uint)]); + sub(bcx, mt.ty) + } _ { - bcx.sess().unimpl("trans::reflect::visit_ty_args on " - + ty_to_str(bcx.ccx().tcx, t)); + // Ideally this would be an unimpl, but sadly we have + // to pretend we can visit everything at this point. + step(bcx, "visit_bot", []) } } } diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index e9caa5f1d4b7..4b92e518b2e4 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -1,7 +1,3 @@ -// xfail-test -// -// This doesn't work quite yet in check-fast mode. Not sure why. Crashes. - enum my_visitor = @{ mut types: [str] }; impl of intrinsic::ty_visitor for my_visitor { From c56b8f8924081def213bf5a4ca25affb50a26fd7 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Jun 2012 20:20:22 -0700 Subject: [PATCH 51/53] Remove unused middle::ty::sort_methods function. --- src/rustc/middle/ty.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index a426ded68f85..ca70c7d70a62 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -63,7 +63,6 @@ export mt; export node_type_table; export pat_ty; export sequence_element_type; -export sort_methods; export stmt_node_id; export sty; export subst, subst_tps, substs_is_noop, substs_to_str, substs; @@ -2311,13 +2310,6 @@ fn method_idx(id: ast::ident, meths: [method]) -> option { ret none; } -fn sort_methods(meths: [method]) -> [method] { - fn method_lteq(a: method, b: method) -> bool { - ret str::le(a.ident, b.ident); - } - ret std::sort::merge_sort(bind method_lteq(_, _), meths); -} - fn occurs_check(tcx: ctxt, sp: span, vid: ty_vid, rt: t) { // Fast path if !type_needs_infer(rt) { ret; } From de4f0b92b631a0a35de6ee118df37102e96e8744 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 21:51:09 -0700 Subject: [PATCH 52/53] Say "easily" instead of "sanely" I can't correct it every time, but every time someone uses "insane"/ "sane" as synonyms for "bad"/"good", they're saying that being like me is the same as being everything that's bad and wrong in the world... so I'm changing this to a word that means approximately the same thing but doesn't devalue any group of people. --- src/libsyntax/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f0a3006b8c67..ab458931b0c0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -313,7 +313,7 @@ enum expr_ { expr_fn(proto, fn_decl, blk, capture_clause), expr_fn_block(fn_decl, blk, capture_clause), // Inner expr is always an expr_fn_block. We need the wrapping node to - // sanely type this (a function returning nil on the inside but bool on + // easily type this (a function returning nil on the inside but bool on // the outside). expr_loop_body(@expr), expr_block(blk), From 0327dc0b188ee536eb6865cf202f03c88864f4fb Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 6 Jun 2012 21:52:41 -0700 Subject: [PATCH 53/53] Insert missing maybe_print_comment call for class destructors While it wasn't the original issue, the first program from #2487 failed the pretty-printing test because of this, so it's still a good test case :-) It also turns out that the second program from #2487 now triggers a kind error, so I figured I might as well add it as a test case. --- src/libsyntax/print/pprust.rs | 1 + src/test/compile-fail/issue-2487-b.rs | 19 +++++++++++++++++++ src/test/run-pass/issue-2487-a.rs | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/compile-fail/issue-2487-b.rs create mode 100644 src/test/run-pass/issue-2487-a.rs diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a8df8d85092b..d4e66137d675 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -539,6 +539,7 @@ fn print_item(s: ps, &&item: @ast::item) { print_block(s, ctor.node.body); option::iter(m_dtor) {|dtor| hardbreak_if_not_bol(s); + maybe_print_comment(s, dtor.span.lo); head(s, "drop"); print_block(s, dtor.node.body); } diff --git a/src/test/compile-fail/issue-2487-b.rs b/src/test/compile-fail/issue-2487-b.rs new file mode 100644 index 000000000000..a1438c531876 --- /dev/null +++ b/src/test/compile-fail/issue-2487-b.rs @@ -0,0 +1,19 @@ +class socket { + let sock: int; + + new() { self.sock = 1; } + + drop { } + + fn set_identity() { + closure { || + setsockopt_bytes(self.sock) //! ERROR copying a noncopyable value + } + } +} + +fn closure(f: fn@()) { f() } + +fn setsockopt_bytes(+_sock: int) { } + +fn main() {} diff --git a/src/test/run-pass/issue-2487-a.rs b/src/test/run-pass/issue-2487-a.rs new file mode 100644 index 000000000000..ab1d9ccb3bea --- /dev/null +++ b/src/test/run-pass/issue-2487-a.rs @@ -0,0 +1,19 @@ +class socket { + let sock: int; + + new() { self.sock = 1; } + + drop { } + + fn set_identity() { + closure { || + setsockopt_bytes(copy self.sock) + } + } +} + +fn closure(f: fn()) { f() } + +fn setsockopt_bytes(_sock: int) { } + +fn main() {}