From e8493115c5f7709ccefb1fd3b6f595746a9d8319 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 5 Jun 2012 21:40:57 -0700 Subject: [PATCH 01/11] 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 c6e16c5668a86245259a4f542a62199b2023b89b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Jun 2012 11:42:53 -0700 Subject: [PATCH 02/11] 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 03/11] 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 cba77ffbfa469727314f65405117277839a1783b Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Wed, 6 Jun 2012 14:28:59 -0700 Subject: [PATCH 04/11] 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 05/11] 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 06/11] 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 07/11] 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 08/11] 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 09/11] 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 107442d99496dbb037bc965d94904f21740f726f Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Jun 2012 16:01:12 -0700 Subject: [PATCH 10/11] 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 11/11] 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 {