diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index f91260f475288..27c8051afac36 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -418,8 +418,8 @@ mod test { fn make_file(path : &Path, contents: &[~str]) { let file = io::file_writer(path, [io::Create, io::Truncate]).get(); - for contents.iter().advance |&str| { - file.write_str(str); + for contents.iter().advance |str| { + file.write_str(*str); file.write_char('\n'); } } @@ -445,7 +445,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true); // 3 files containing 0\n, 1\n, and 2\n respectively - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -475,7 +475,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true); // 3 files containing 1\n, 2\n, and 3\n respectively - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -495,10 +495,11 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j)); make_file(filename.get_ref(), contents); + debug!("contents=%?", contents); all_lines.push_all(contents); } @@ -515,7 +516,7 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); make_file(filename.get_ref(), contents); @@ -579,10 +580,10 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); - make_file(&filename.get(), contents); + make_file(filename.get_ref(), contents); } let in = FileInput::from_vec(filenames); diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index a0b95924e09dc..5867b13f55656 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -1571,10 +1571,10 @@ mod biguint_tests { fn test_to_str_radix() { let r = to_str_pairs(); for r.iter().advance |num_pair| { - let &(n, rs) = num_pair; + let &(ref n, ref rs) = num_pair; for rs.iter().advance |str_pair| { - let &(radix, str) = str_pair; - assert_eq!(n.to_str_radix(radix), str); + let &(ref radix, ref str) = str_pair; + assert_eq!(&n.to_str_radix(*radix), str); } } } @@ -1583,10 +1583,10 @@ mod biguint_tests { fn test_from_str_radix() { let r = to_str_pairs(); for r.iter().advance |num_pair| { - let &(n, rs) = num_pair; + let &(ref n, ref rs) = num_pair; for rs.iter().advance |str_pair| { - let &(radix, str) = str_pair; - assert_eq!(&n, &FromStrRadix::from_str_radix(str, radix).get()); + let &(ref radix, ref str) = str_pair; + assert_eq!(n, &FromStrRadix::from_str_radix(*str, *radix).get()); } } diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs index 86080b343c78b..7cc8bca891077 100644 --- a/src/libextra/rc.rs +++ b/src/libextra/rc.rs @@ -73,7 +73,7 @@ impl Drop for Rc { if self.ptr.is_not_null() { (*self.ptr).count -= 1; if (*self.ptr).count == 0 { - ptr::replace_ptr(self.ptr, intrinsics::uninit()); + ptr::read_ptr(self.ptr); free(self.ptr as *c_void) } } diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 5562662277576..cd226e2ad3267 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -119,8 +119,8 @@ impl Terminal { pub fn reset(&self) { let mut vars = Variables::new(); let s = do self.ti.strings.find_equiv(&("op")) - .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| { - expand(op, [], &mut vars) + .map_consume_default(Err(~"can't find terminfo capability `op`")) |op| { + expand(copy *op, [], &mut vars) }; if s.is_ok() { self.out.write(s.unwrap()); diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index b7d21ea0ee3fd..f25d192cc0a9f 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -81,8 +81,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) // Copy parameters into a local vector for mutability let mut mparams = [Number(0), ..9]; - for mparams.mut_iter().zip(params.iter()).advance |(dst, &src)| { - *dst = src; + for mparams.mut_iter().zip(params.iter()).advance |(dst, src)| { + *dst = copy *src; } for cap.iter().transform(|&x| x).advance |c| { diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index a5f7479d41a01..f2dea8b9bbaf3 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -773,15 +773,15 @@ mod test_treemap { map: &TreeMap) { assert_eq!(ctrl.is_empty(), map.is_empty()); for ctrl.iter().advance |x| { - let &(k, v) = x; - assert!(map.find(&k).unwrap() == &v) + let &(ref k, ref v) = x; + assert!(map.find(k).unwrap() == v) } for map.iter().advance |(map_k, map_v)| { let mut found = false; for ctrl.iter().advance |x| { - let &(ctrl_k, ctrl_v) = x; - if *map_k == ctrl_k { - assert!(*map_v == ctrl_v); + let &(ref ctrl_k, ref ctrl_v) = x; + if *map_k == *ctrl_k { + assert!(*map_v == *ctrl_v); found = true; break; } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 503bd05b7337d..e7bec2fbd8d1c 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -157,8 +157,8 @@ impl Decodable for WorkMap { fn decode(d: &mut D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); let mut w = WorkMap::new(); - for v.iter().advance |&(k, v)| { - w.insert(copy k, copy v); + for v.iter().advance |pair| { + w.insert(pair.first(), pair.second()); } w } diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs index c1192707c1c15..f9dc88074d3b1 100644 --- a/src/librustc/back/passes.rs +++ b/src/librustc/back/passes.rs @@ -165,10 +165,10 @@ pub fn create_standard_passes(level: OptLevel) -> ~[~str] { } pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) { - for pass_list.iter().advance |&nm| { - match create_pass(nm) { + for pass_list.iter().advance |nm| { + match create_pass(*nm) { Some(p) => pm.add_pass(p), - None => sess.warn(fmt!("Unknown pass %s", nm)) + None => sess.warn(fmt!("Unknown pass %s", *nm)) } } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 3c50754744886..e8ef95b811e87 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -314,7 +314,6 @@ pub fn compile_rest(sess: Session, method_map: method_map, vtable_map: vtable_map, write_guard_map: write_guard_map, - moves_map: moves_map, capture_map: capture_map }; diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 31577e472678e..9aefb8fdb5579 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -127,7 +127,9 @@ fn find_library_crate_aux( cx.diag.span_err( cx.span, fmt!("multiple matching crates for `%s`", crate_name)); cx.diag.handler().note("candidates:"); - for matches.iter().advance |&(ident, data)| { + for matches.iter().advance |pair| { + let ident = pair.first(); + let data = pair.second(); cx.diag.handler().note(fmt!("path: %s", ident)); let attrs = decoder::get_crate_attributes(data); note_linkage_attrs(cx.intr, cx.diag, attrs); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 72b6f8e1c805b..7412eba115631 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -53,7 +53,6 @@ pub struct Maps { method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, write_guard_map: middle::borrowck::write_guard_map, - moves_map: middle::moves::MovesMap, capture_map: middle::moves::CaptureMap, } @@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } - if maps.moves_map.contains(&id) { - do ebml_w.tag(c::tag_table_moves_map) |ebml_w| { - ebml_w.id(id); - } - } - { let r = maps.capture_map.find(&id); for r.iter().advance |&cap_vars| { @@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, xcx.dcx.tcx.sess.bug( fmt!("unknown tag found in side tables: %x", tag)); } - Some(value) => if value == c::tag_table_moves_map { - dcx.maps.moves_map.insert(id); - } else { + Some(value) => { let val_doc = entry_doc.get(c::tag_table_val as uint); let mut val_dsr = reader::Decoder(val_doc); let val_dsr = &mut val_dsr; diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index b2e303d40eecf..a455bdc436cad 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -65,7 +65,7 @@ pub fn check_loans(bccx: @BorrowckCtxt, enum MoveError { MoveOk, - MoveWhileBorrowed(/*move*/@LoanPath, /*loan*/@LoanPath, /*loan*/span) + MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span) } impl<'self> CheckLoanCtxt<'self> { @@ -348,7 +348,7 @@ impl<'self> CheckLoanCtxt<'self> { cmt = b; } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -547,45 +547,50 @@ impl<'self> CheckLoanCtxt<'self> { self.bccx.loan_path_to_str(loan_path))); } - pub fn check_move_out_from_expr(&self, ex: @ast::expr) { - match ex.node { - ast::expr_paren(*) => { - /* In the case of an expr_paren(), the expression inside - * the parens will also be marked as being moved. Ignore - * the parents then so as not to report duplicate errors. */ + fn check_move_out_from_expr(&self, expr: @ast::expr) { + match expr.node { + ast::expr_fn_block(*) => { + // moves due to capture clauses are checked + // in `check_loans_in_fn`, so that we can + // give a better error message } _ => { - let cmt = self.bccx.cat_expr(ex); - match self.analyze_move_out_from_cmt(cmt) { - MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { - self.bccx.span_err( - cmt.span, - fmt!("cannot move out of `%s` \ - because it is borrowed", - self.bccx.loan_path_to_str(move_path))); - self.bccx.span_note( - loan_span, - fmt!("borrow of `%s` occurs here", - self.bccx.loan_path_to_str(loan_path))); - } + self.check_move_out_from_id(expr.id, expr.span) + } + } + } + + fn check_move_out_from_id(&self, id: ast::node_id, span: span) { + for self.move_data.each_path_moved_by(id) |_, move_path| { + match self.analyze_move_out_from(id, move_path) { + MoveOk => {} + MoveWhileBorrowed(loan_path, loan_span) => { + self.bccx.span_err( + span, + fmt!("cannot move out of `%s` \ + because it is borrowed", + self.bccx.loan_path_to_str(move_path))); + self.bccx.span_note( + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } } - pub fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError { - debug!("analyze_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx())); + pub fn analyze_move_out_from(&self, + expr_id: ast::node_id, + move_path: @LoanPath) -> MoveError { + debug!("analyze_move_out_from(expr_id=%?, move_path=%s)", + expr_id, move_path.repr(self.tcx())); // FIXME(#4384) inadequare if/when we permit `move a.b` // check for a conflicting loan: - let r = opt_loan_path(cmt); - for r.iter().advance |&lp| { - for self.each_in_scope_restriction(cmt.id, lp) |loan, _| { - // Any restriction prevents moves. - return MoveWhileBorrowed(lp, loan.loan_path, loan.span); - } + for self.each_in_scope_restriction(expr_id, move_path) |loan, _| { + // Any restriction prevents moves. + return MoveWhileBorrowed(loan.loan_path, loan.span); } MoveOk @@ -652,13 +657,11 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, closure_id: ast::node_id, cap_var: &moves::CaptureVar) { let var_id = ast_util::def_id_of_def(cap_var.def).node; - let ty = ty::node_id_to_type(this.tcx(), var_id); - let cmt = this.bccx.cat_def(closure_id, cap_var.span, - ty, cap_var.def); - let move_err = this.analyze_move_out_from_cmt(cmt); + let move_path = @LpVar(var_id); + let move_err = this.analyze_move_out_from(closure_id, move_path); match move_err { MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { + MoveWhileBorrowed(loan_path, loan_span) => { this.bccx.span_err( cap_var.span, fmt!("cannot move `%s` into closure \ @@ -689,10 +692,7 @@ fn check_loans_in_expr<'a>(expr: @ast::expr, expr.repr(this.tcx())); this.check_for_conflicting_loans(expr.id); - - if this.bccx.moves_map.contains(&expr.id) { - this.check_move_out_from_expr(expr); - } + this.check_move_out_from_expr(expr); match expr.node { ast::expr_self | @@ -742,18 +742,7 @@ fn check_loans_in_pat<'a>(pat: @ast::pat, visit::vt<@mut CheckLoanCtxt<'a>>)) { this.check_for_conflicting_loans(pat.id); - - // Note: moves out of pattern bindings are not checked by - // the borrow checker, at least not directly. What happens - // is that if there are any moved bindings, the discriminant - // will be considered a move, and this will be checked as - // normal. Then, in `middle::check_match`, we will check - // that no move occurs in a binding that is underneath an - // `@` or `&`. Together these give the same guarantees as - // `check_move_out_from_expr()` without requiring us to - // rewalk the patterns and rebuild the pattern - // categorizations. - + this.check_move_out_from_id(pat.id, pat.span); visit::visit_pat(pat, (this, vt)); } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 05fc139305c4a..5d91916d0044a 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -67,7 +67,7 @@ impl GuaranteeLifetimeContext { //! Main routine. Walks down `cmt` until we find the "guarantor". match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_implicit_self | mc::cat_copied_upvar(*) | // L-Local mc::cat_local(*) | // L-Local @@ -179,7 +179,7 @@ impl GuaranteeLifetimeContext { //! lvalue. cmt.mutbl.is_immutable() || match cmt.guarantor().cat { - mc::cat_rvalue => true, + mc::cat_rvalue(*) => true, _ => false } } @@ -299,7 +299,7 @@ impl GuaranteeLifetimeContext { mc::cat_arg(id) => { self.bccx.moved_variables_set.contains(&id) } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -325,8 +325,8 @@ impl GuaranteeLifetimeContext { // See the SCOPE(LV) function in doc.rs match cmt.cat { - mc::cat_rvalue => { - ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id)) + mc::cat_rvalue(cleanup_scope_id) => { + ty::re_scope(cleanup_scope_id) } mc::cat_implicit_self | mc::cat_copied_upvar(_) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 26fa4924ccb52..23451e0f36ea0 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -73,6 +73,7 @@ struct GatherLoanCtxt { } pub fn gather_loans(bccx: @BorrowckCtxt, + decl: &ast::fn_decl, body: &ast::blk) -> (id_range, @mut ~[Loan], @mut move_data::MoveData) { let glcx = @mut GatherLoanCtxt { @@ -83,6 +84,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt, repeating_ids: ~[body.node.id], move_data: @mut MoveData::new() }; + glcx.gather_fn_arg_patterns(decl, body); let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, visit_block: gather_loans_in_block, visit_fn: gather_loans_in_fn, @@ -124,6 +126,7 @@ fn gather_loans_in_fn(fk: &visit::fn_kind, this.push_repeating_id(body.node.id); visit::visit_fn(fk, decl, body, sp, id, (this, v)); this.pop_repeating_id(body.node.id); + this.gather_fn_arg_patterns(decl, body); } } } @@ -138,26 +141,33 @@ fn gather_loans_in_block(blk: &ast::blk, fn gather_loans_in_local(local: @ast::local, (this, vt): (@mut GatherLoanCtxt, visit::vt<@mut GatherLoanCtxt>)) { - if local.node.init.is_none() { - // Variable declarations without initializers are considered "moves": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_decl(this.bccx, - this.move_data, - id, - span, - id); + match local.node.init { + None => { + // Variable declarations without initializers are considered "moves": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_decl(this.bccx, + this.move_data, + id, + span, + id); + } } - } else { - // Variable declarations with initializers are considered "assigns": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_assignment(this.bccx, - this.move_data, - id, - span, - @LpVar(id), - id); + Some(init) => { + // Variable declarations with initializers are considered "assigns": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_assignment(this.bccx, + this.move_data, + id, + span, + @LpVar(id), + id); + } + let init_cmt = this.bccx.cat_expr(init); + this.gather_pat(init_cmt, local.node.pat, None); } } @@ -230,7 +240,7 @@ fn gather_loans_in_expr(ex: @ast::expr, let cmt = this.bccx.cat_expr(ex_v); for arms.iter().advance |arm| { for arm.pats.iter().advance |pat| { - this.gather_pat(cmt, *pat, arm.body.node.id, ex.id); + this.gather_pat(cmt, *pat, Some((arm.body.node.id, ex.id))); } } visit::visit_expr(ex, (this, vt)); @@ -596,11 +606,40 @@ impl GatherLoanCtxt { } } - pub fn gather_pat(&mut self, - discr_cmt: mc::cmt, - root_pat: @ast::pat, - arm_body_id: ast::node_id, - match_id: ast::node_id) { + fn gather_fn_arg_patterns(&mut self, + decl: &ast::fn_decl, + body: &ast::blk) { + /*! + * Walks the patterns for fn arguments, checking that they + * do not attempt illegal moves or create refs that outlive + * the arguments themselves. Just a shallow wrapper around + * `gather_pat()`. + */ + + let mc_ctxt = self.bccx.mc_ctxt(); + for decl.inputs.iter().advance |arg| { + let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id); + + let arg_cmt = mc_ctxt.cat_rvalue( + arg.id, + arg.pat.span, + body.node.id, // Arguments live only as long as the fn body. + arg_ty); + + self.gather_pat(arg_cmt, arg.pat, None); + } + } + + fn gather_pat(&mut self, + discr_cmt: mc::cmt, + root_pat: @ast::pat, + arm_match_ids: Option<(ast::node_id, ast::node_id)>) { + /*! + * Walks patterns, examining the bindings to determine if they + * cause borrows (`ref` bindings, vector patterns) or + * moves (non-`ref` bindings with linear type). + */ + do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { match pat.node { ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { @@ -621,15 +660,19 @@ impl GatherLoanCtxt { // with a cat_discr() node. There is a detailed // discussion of the function of this node in // `lifetime.rs`: - let arm_scope = ty::re_scope(arm_body_id); - if self.bccx.is_subregion_of(scope_r, arm_scope) { - let cmt_discr = self.bccx.cat_discr(cmt, match_id); - self.guarantee_valid(pat.id, pat.span, - cmt_discr, mutbl, scope_r); - } else { - self.guarantee_valid(pat.id, pat.span, - cmt, mutbl, scope_r); - } + let cmt_discr = match arm_match_ids { + None => cmt, + Some((arm_id, match_id)) => { + let arm_scope = ty::re_scope(arm_id); + if self.bccx.is_subregion_of(scope_r, arm_scope) { + self.bccx.cat_discr(cmt, match_id) + } else { + cmt + } + } + }; + self.guarantee_valid(pat.id, pat.span, + cmt_discr, mutbl, scope_r); } ast::bind_infer => { // No borrows here, but there may be moves @@ -652,6 +695,24 @@ impl GatherLoanCtxt { self.vec_slice_info(slice_pat, slice_ty); let mcx = self.bccx.mc_ctxt(); let cmt_index = mcx.cat_index(slice_pat, cmt, 0); + + // Note: We declare here that the borrow occurs upon + // entering the `[...]` pattern. This implies that + // something like `[a, ..b]` where `a` is a move is + // illegal, because the borrow is already in effect. + // In fact such a move would be safe-ish, but it + // effectively *requires* that we use the nulling + // out semantics to indicate when a value has been + // moved, which we are trying to move away from. + // Otherwise, how can we indicate that the first + // element in the vector has been moved? + // Eventually, we could perhaps modify this rule to + // permit `[..a, b]` where `b` is a move, because in + // that case we can adjust the length of the + // original vec accordingly, but we'd have to make + // trans do the right thing, and it would only work + // for `~` vectors. It seems simpler to just require + // that people call `vec.pop()` or `vec.unshift()`. self.guarantee_valid(pat.id, pat.span, cmt_index, slice_mutbl, slice_r); } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index d5377aeb61839..e568da5eedfae 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -64,7 +64,7 @@ impl RestrictionsContext { } match cmt.cat { - mc::cat_rvalue => { + mc::cat_rvalue(*) => { // Effectively, rvalues are stored into a // non-aliasable temporary on the stack. Since they // are inherently non-aliasable, they can only be diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 2e3813f57e081..47d35d73df09b 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -124,7 +124,7 @@ fn borrowck_fn(fk: &visit::fn_kind, // Check the body of fn items. let (id_range, all_loans, move_data) = - gather_loans::gather_loans(this, body); + gather_loans::gather_loans(this, decl, body); let mut loan_dfcx = DataFlowContext::new(this.tcx, this.method_map, @@ -264,7 +264,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { //! traverses the CMT. match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_copied_upvar(_) | mc::cat_implicit_self => { @@ -485,7 +485,7 @@ impl BorrowckCtxt { pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt { mc::mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map} + method_map: self.method_map} } pub fn cat_pattern(&self, diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 73adade7a5d71..7ec1ff3c628e4 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -474,6 +474,24 @@ impl FlowedMoveData { } } + pub fn each_path_moved_by(&self, + id: ast::node_id, + f: &fn(&Move, @LoanPath) -> bool) + -> bool { + /*! + * Iterates through each path moved by `id` + */ + + for self.dfcx_moves.each_gen_bit_frozen(id) |index| { + let move = &self.move_data.moves[index]; + let moved_path = move.path; + if !f(move, self.move_data.path(moved_path).loan_path) { + return false; + } + } + return true; + } + pub fn each_move_of(&self, id: ast::node_id, loan_path: @LoanPath, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 0baeb8ce57c6c..02f7294ffcd3b 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -49,23 +49,13 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); } -pub fn expr_is_non_moving_lvalue(cx: &MatchCheckCtxt, expr: &expr) -> bool { - if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) { - return false; - } - - !cx.moves_map.contains(&expr.id) -} - pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) { visit::visit_expr(ex, (s, v)); match ex.node { expr_match(scrut, ref arms) => { // First, check legality of move bindings. - let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex); for arms.iter().advance |arm| { check_legality_of_move_bindings(cx, - is_non_moving_lvalue, arm.guard.is_some(), arm.pats); } @@ -758,11 +748,7 @@ pub fn check_local(cx: &MatchCheckCtxt, } // Check legality of move bindings. - let is_lvalue = match loc.node.init { - Some(init) => expr_is_non_moving_lvalue(cx, init), - None => true - }; - check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]); + check_legality_of_move_bindings(cx, false, [ loc.node.pat ]); } pub fn check_fn(cx: &MatchCheckCtxt, @@ -821,7 +807,6 @@ pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool { // Legality of move bindings checking pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, - is_lvalue: bool, has_guard: bool, pats: &[@pat]) { let tcx = cx.tcx; @@ -861,11 +846,6 @@ pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, tcx.sess.span_note( by_ref_span.get(), "by-ref binding occurs here"); - } else if is_lvalue { - tcx.sess.span_err( - p.span, - "cannot bind by-move when \ - matching an lvalue"); } }; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bf91b6771dcd8..af39dea6d79e1 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -187,7 +187,6 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, method_map: @mut HashMap::new(), vtable_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), - moves_map: @mut HashSet::new(), capture_map: @mut HashMap::new() }; match csearch::maybe_get_item_ast(tcx, def_id, diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index e054b84984d15..ec375eaba0e86 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -422,8 +422,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { loop_scopes: &mut ~[LoopScope]) { match decl.node { ast::decl_local(local) => { - self.walk_pat(local.node.pat, in_out, loop_scopes); self.walk_opt_expr(local.node.init, in_out, loop_scopes); + self.walk_pat(local.node.pat, in_out, loop_scopes); } ast::decl_item(_) => {} diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fd36858ba6880..ac7805146e486 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -60,7 +60,7 @@ use syntax::print::pprust; #[deriving(Eq)] pub enum categorization { - cat_rvalue, // result of eval'ing some misc expr + cat_rvalue(ast::node_id), // temporary val, argument is its scope cat_static_item, cat_implicit_self, cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env @@ -350,7 +350,7 @@ impl mem_categorization_ctxt { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -360,7 +360,7 @@ impl mem_categorization_ctxt { // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -390,7 +390,7 @@ impl mem_categorization_ctxt { match expr.node { ast::expr_unary(_, ast::deref, e_base) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(e_base); @@ -408,7 +408,7 @@ impl mem_categorization_ctxt { ast::expr_index(_, base, _) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(base); @@ -433,7 +433,7 @@ impl mem_categorization_ctxt { ast::expr_match(*) | ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) | ast::expr_again(*) | ast::expr_struct(*) | ast::expr_repeat(*) | ast::expr_inline_asm(*) => { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } } } @@ -577,11 +577,24 @@ impl mem_categorization_ctxt { } } - pub fn cat_rvalue(&self, elt: N, expr_ty: ty::t) -> cmt { + pub fn cat_rvalue_node(&self, + node: N, + expr_ty: ty::t) -> cmt { + self.cat_rvalue(node.id(), + node.span(), + self.tcx.region_maps.cleanup_scope(node.id()), + expr_ty) + } + + pub fn cat_rvalue(&self, + cmt_id: ast::node_id, + span: span, + cleanup_scope_id: ast::node_id, + expr_ty: ty::t) -> cmt { @cmt_ { - id:elt.id(), - span:elt.span(), - cat:cat_rvalue, + id:cmt_id, + span:span, + cat:cat_rvalue(cleanup_scope_id), mutbl:McDeclared, ty:expr_ty } @@ -970,7 +983,7 @@ impl mem_categorization_ctxt { } for slice.iter().advance |&slice_pat| { let slice_ty = self.pat_ty(slice_pat); - let slice_cmt = self.cat_rvalue(pat, slice_ty); + let slice_cmt = self.cat_rvalue_node(pat, slice_ty); self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } for after.iter().advance |&after_pat| { @@ -1003,7 +1016,7 @@ impl mem_categorization_ctxt { cat_copied_upvar(_) => { ~"captured outer variable in a heap closure" } - cat_rvalue => { + cat_rvalue(*) => { ~"non-lvalue" } cat_local(_) => { @@ -1100,7 +1113,7 @@ impl cmt_ { //! determines how long the value in `self` remains live. match self.cat { - cat_rvalue | + cat_rvalue(*) | cat_static_item | cat_implicit_self | cat_copied_upvar(*) | @@ -1187,11 +1200,13 @@ impl Repr for categorization { match *self { cat_static_item | cat_implicit_self | - cat_rvalue | + cat_rvalue(*) | cat_copied_upvar(*) | cat_local(*) | cat_self(*) | - cat_arg(*) => fmt!("%?", *self), + cat_arg(*) => { + fmt!("%?", *self) + } cat_deref(cmt, derefs, ptr) => { fmt!("%s->(%s, %u)", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs) @@ -1205,7 +1220,9 @@ impl Repr for categorization { fmt!("%s->(enum)", cmt.cat.repr(tcx)) } cat_stack_upvar(cmt) | - cat_discr(cmt, _) => cmt.cat.repr(tcx) + cat_discr(cmt, _) => { + cmt.cat.repr(tcx) + } } } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index f3d4abcdf310f..07bdee07c0feb 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -193,7 +193,9 @@ pub fn compute_moves(tcx: ty::ctxt, crate: &crate) -> MoveMaps { let visitor = visit::mk_vt(@visit::Visitor { + visit_fn: compute_modes_for_fn, visit_expr: compute_modes_for_expr, + visit_local: compute_modes_for_local, .. *visit::default_visitor() }); let visit_cx = VisitContext { @@ -220,9 +222,31 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option { } } -// ______________________________________________________________________ +/////////////////////////////////////////////////////////////////////////// // Expressions +fn compute_modes_for_local<'a>(local: @local, + (cx, v): (VisitContext, + vt)) { + cx.use_pat(local.node.pat); + for local.node.init.iter().advance |&init| { + cx.use_expr(init, Read, v); + } +} + +fn compute_modes_for_fn(fk: &visit::fn_kind, + decl: &fn_decl, + body: &blk, + span: span, + id: node_id, + (cx, v): (VisitContext, + vt)) { + for decl.inputs.iter().advance |a| { + cx.use_pat(a.pat); + } + visit::visit_fn(fk, decl, body, span, id, (cx, v)); +} + fn compute_modes_for_expr(expr: @expr, (cx, v): (VisitContext, vt)) @@ -522,7 +546,10 @@ impl VisitContext { self.use_expr(base, comp_mode, visitor); } - expr_fn_block(_, ref body) => { + expr_fn_block(ref decl, ref body) => { + for decl.inputs.iter().advance |a| { + self.use_pat(a.pat); + } let cap_vars = self.compute_captures(expr.id); self.move_maps.capture_map.insert(expr.id, cap_vars); self.consume_block(body, visitor); @@ -580,13 +607,15 @@ impl VisitContext { * into itself or not based on its type and annotation. */ - do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, _path| { + do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| { let binding_moves = match bm { bind_by_ref(_) => false, bind_infer => { let pat_ty = ty::node_id_to_type(self.tcx, id); - debug!("pattern %? type is %s", - id, pat_ty.repr(self.tcx)); + debug!("pattern %? %s type is %s", + id, + ast_util::path_to_ident(path).repr(self.tcx), + pat_ty.repr(self.tcx)); ty::type_moves_by_default(self.tcx, pat_ty) } }; diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index b7168cbfdec53..d5d0cde1ee0a0 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -268,7 +268,7 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { } lit(UnitLikeStructLit(pat_id)) => { let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id); - let datumblock = datum::scratch_datum(bcx, struct_ty, true); + let datumblock = datum::scratch_datum(bcx, struct_ty, "", true); return single_result(datumblock.to_result(bcx)); } lit(ConstLit(lit_id)) => { @@ -316,7 +316,7 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id) } pub enum TransBindingMode { - TrByValue(/*ismove:*/ bool, /*llbinding:*/ ValueRef), + TrByValue(/*llbinding:*/ ValueRef), TrByRef, } @@ -927,7 +927,7 @@ pub fn extract_vec_elems(bcx: block, ty::mt {ty: vt.unit_ty, mutbl: ast::m_imm}, ty::vstore_slice(ty::re_static) ); - let scratch = scratch_datum(bcx, slice_ty, false); + let scratch = scratch_datum(bcx, slice_ty, "", false); Store(bcx, slice_begin, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]) ); @@ -1095,9 +1095,9 @@ pub fn compare_values(cx: block, match ty::get(rhs_t).sty { ty::ty_estr(ty::vstore_uniq) => { - let scratch_lhs = alloca(cx, val_ty(lhs)); + let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs"); Store(cx, lhs, scratch_lhs); - let scratch_rhs = alloca(cx, val_ty(rhs)); + let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs"); Store(cx, rhs, scratch_rhs); let did = cx.tcx().lang_items.uniq_str_eq_fn(); let result = callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None); @@ -1138,18 +1138,11 @@ fn store_non_ref_bindings(bcx: block, let mut bcx = bcx; for bindings_map.each_value |&binding_info| { match binding_info.trmode { - TrByValue(is_move, lldest) => { + TrByValue(lldest) => { let llval = Load(bcx, binding_info.llmatch); // get a T* let datum = Datum {val: llval, ty: binding_info.ty, mode: ByRef(ZeroMem)}; - bcx = { - if is_move { - datum.move_to(bcx, INIT, lldest) - } else { - datum.copy_to(bcx, INIT, lldest) - } - }; - + bcx = datum.store_to(bcx, INIT, lldest); do opt_temp_cleanups.mutate |temp_cleanups| { add_clean_temp_mem(bcx, lldest, binding_info.ty); temp_cleanups.push(lldest); @@ -1181,7 +1174,7 @@ fn insert_lllocals(bcx: block, let llval = match binding_info.trmode { // By value bindings: use the stack slot that we // copied/moved the value into - TrByValue(_, lldest) => { + TrByValue(lldest) => { if add_cleans { add_clean(bcx, lldest, binding_info.ty); } @@ -1245,7 +1238,7 @@ pub fn compile_guard(bcx: block, let mut bcx = bcx; for data.bindings_map.each_value |&binding_info| { match binding_info.trmode { - TrByValue(_, llval) => { + TrByValue(llval) => { bcx = glue::drop_ty(bcx, llval, binding_info.ty); } TrByRef => {} @@ -1636,12 +1629,12 @@ fn create_bindings_map(bcx: block, pat: @ast::pat) -> BindingsMap { // in this case, the final type of the variable will be T, // but during matching we need to store a *T as explained // above - let is_move = ccx.maps.moves_map.contains(&p_id); - llmatch = alloca(bcx, llvariable_ty.ptr_to()); - trmode = TrByValue(is_move, alloca(bcx, llvariable_ty)); + llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch"); + trmode = TrByValue(alloca(bcx, llvariable_ty, + bcx.ident(ident))); } ast::bind_by_ref(_) => { - llmatch = alloca(bcx, llvariable_ty); + llmatch = alloca(bcx, llvariable_ty, bcx.ident(ident)); trmode = TrByRef; } }; @@ -1737,53 +1730,205 @@ pub enum IrrefutablePatternBindingMode { BindArgument } -// Not match-related, but similar to the pattern-munging code above -pub fn bind_irrefutable_pat(bcx: block, - pat: @ast::pat, - val: ValueRef, - make_copy: bool, - binding_mode: IrrefutablePatternBindingMode) - -> block { - let _icx = push_ctxt("match::bind_irrefutable_pat"); - let ccx = bcx.fcx.ccx; +pub fn store_local(bcx: block, + pat: @ast::pat, + opt_init_expr: Option<@ast::expr>) + -> block { + /*! + * Generates code for a local variable declaration like + * `let ;` or `let = `. + */ + let _icx = push_ctxt("match::store_local"); let mut bcx = bcx; - // Necessary since bind_irrefutable_pat is called outside trans_match - match pat.node { - ast::pat_ident(_, _, ref inner) => { - if pat_is_variant_or_struct(bcx.tcx().def_map, pat) { - return bcx; + return match opt_init_expr { + Some(init_expr) => { + // Optimize the "let x = expr" case. This just writes + // the result of evaluating `expr` directly into the alloca + // for `x`. Often the general path results in similar or the + // same code post-optimization, but not always. In particular, + // in unsafe code, you can have expressions like + // + // let x = intrinsics::uninit(); + // + // In such cases, the more general path is unsafe, because + // it assumes it is matching against a valid value. + match simple_identifier(pat) { + Some(path) => { + return mk_binding_alloca( + bcx, pat.id, path, BindLocal, + |bcx, _, llval| expr::trans_into(bcx, init_expr, + expr::SaveIn(llval))); + } + + None => {} } - if make_copy { - let binding_ty = node_id_type(bcx, pat.id); - let datum = Datum {val: val, ty: binding_ty, - mode: ByRef(RevokeClean)}; - let scratch = scratch_datum(bcx, binding_ty, false); - datum.copy_to_datum(bcx, INIT, scratch); - match binding_mode { - BindLocal => { - bcx.fcx.lllocals.insert(pat.id, scratch.val); - } - BindArgument => { - bcx.fcx.llargs.insert(pat.id, scratch.val); - } - } - add_clean(bcx, scratch.val, binding_ty); + // General path. + let init_datum = + unpack_datum!( + bcx, + expr::trans_to_datum(bcx, init_expr)); + if ty::type_is_bot(expr_ty(bcx, init_expr)) { + create_dummy_locals(bcx, pat) } else { - match binding_mode { - BindLocal => { - bcx.fcx.lllocals.insert(pat.id, val); - } - BindArgument => { - bcx.fcx.llargs.insert(pat.id, val); - } + if bcx.sess().asm_comments() { + add_comment(bcx, "creating zeroable ref llval"); } + let llptr = init_datum.to_zeroable_ref_llval(bcx); + return bind_irrefutable_pat(bcx, pat, llptr, BindLocal); + } + } + None => { + create_dummy_locals(bcx, pat) + } + }; + + fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block { + // create dummy memory for the variables if we have no + // value to store into them immediately + let tcx = bcx.tcx(); + do pat_bindings(tcx.def_map, pat) |_, p_id, _, path| { + bcx = mk_binding_alloca( + bcx, p_id, path, BindLocal, + |bcx, var_ty, llval| { zero_mem(bcx, llval, var_ty); bcx }); + } + bcx + } +} + +pub fn store_arg(mut bcx: block, + pat: @ast::pat, + llval: ValueRef) + -> block { + /*! + * Generates code for argument patterns like `fn foo(: T)`. + * Creates entries in the `llargs` map for each of the bindings + * in `pat`. + * + * # Arguments + * + * - `pat` is the argument pattern + * - `llval` is a pointer to the argument value (in other words, + * if the argument type is `T`, then `llval` is a `T*`). In some + * cases, this code may zero out the memory `llval` points at. + */ + let _icx = push_ctxt("match::store_arg"); + + // We always need to cleanup the argument as we exit the fn scope. + // Note that we cannot do it before for fear of a fn like + // fn getaddr(~ref x: ~uint) -> *uint {....} + // (From test `run-pass/func-arg-ref-pattern.rs`) + let arg_ty = node_id_type(bcx, pat.id); + add_clean(bcx, llval, arg_ty); + + match simple_identifier(pat) { + Some(_) => { + // Optimized path for `x: T` case. This just adopts + // `llval` wholesale as the pointer for `x`, avoiding the + // general logic which may copy out of `llval`. + bcx.fcx.llargs.insert(pat.id, llval); + } + + None => { + // General path. Copy out the values that are used in the + // pattern. + bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument); + } + } + + return bcx; +} + +fn mk_binding_alloca(mut bcx: block, + p_id: ast::node_id, + path: &ast::Path, + binding_mode: IrrefutablePatternBindingMode, + populate: &fn(block, ty::t, ValueRef) -> block) -> block { + let var_ty = node_id_type(bcx, p_id); + let ident = ast_util::path_to_ident(path); + let llval = alloc_ty(bcx, var_ty, bcx.ident(ident)); + bcx = populate(bcx, var_ty, llval); + let llmap = match binding_mode { + BindLocal => bcx.fcx.lllocals, + BindArgument => bcx.fcx.llargs + }; + llmap.insert(p_id, llval); + add_clean(bcx, llval, var_ty); + return bcx; +} + +fn bind_irrefutable_pat(bcx: block, + pat: @ast::pat, + val: ValueRef, + binding_mode: IrrefutablePatternBindingMode) + -> block { + /*! + * A simple version of the pattern matching code that only handles + * irrefutable patterns. This is used in let/argument patterns, + * not in match statements. Unifying this code with the code above + * sounds nice, but in practice it produces very inefficient code, + * since the match code is so much more general. In most cases, + * LLVM is able to optimize the code, but it causes longer compile + * times and makes the generated code nigh impossible to read. + * + * # Arguments + * - bcx: starting basic block context + * - pat: the irrefutable pattern being matched. + * - val: a pointer to the value being matched. If pat matches a value + * of type T, then this is a T*. If the value is moved from `pat`, + * then `*pat` will be zeroed; otherwise, it's existing cleanup + * applies. + * - binding_mode: is this for an argument or a local variable? + */ + + debug!("bind_irrefutable_pat(bcx=%s, pat=%s, binding_mode=%?)", + bcx.to_str(), + pat_to_str(pat, bcx.sess().intr()), + binding_mode); + + if bcx.sess().asm_comments() { + add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)", + pat_to_str(pat, bcx.sess().intr()))); + } + + let _indenter = indenter(); + + let _icx = push_ctxt("alt::bind_irrefutable_pat"); + let mut bcx = bcx; + let tcx = bcx.tcx(); + let ccx = bcx.ccx(); + match pat.node { + ast::pat_ident(pat_binding_mode, ref path, inner) => { + if pat_is_binding(tcx.def_map, pat) { + // Allocate the stack slot where the value of this + // binding will live and place it into the appropriate + // map. + bcx = mk_binding_alloca( + bcx, pat.id, path, binding_mode, + |bcx, variable_ty, llvariable_val| { + match pat_binding_mode { + ast::bind_infer => { + // By value binding: move the value that `val` + // points at into the binding's stack slot. + let datum = Datum {val: val, + ty: variable_ty, + mode: ByRef(ZeroMem)}; + datum.store_to(bcx, INIT, llvariable_val) + } + + ast::bind_by_ref(_) => { + // By ref binding: the value of the variable + // is the pointer `val` itself. + Store(bcx, val, llvariable_val); + bcx + } + } + }); } - for inner.iter().advance |inner_pat| { - bcx = bind_irrefutable_pat( - bcx, *inner_pat, val, true, binding_mode); + for inner.iter().advance |&inner_pat| { + bcx = bind_irrefutable_pat(bcx, inner_pat, val, binding_mode); } } ast::pat_enum(_, ref sub_pats) => { @@ -1799,11 +1944,8 @@ pub fn bind_irrefutable_pat(bcx: block, val); for sub_pats.iter().advance |sub_pat| { for args.vals.iter().enumerate().advance |(i, argval)| { - bcx = bind_irrefutable_pat(bcx, - sub_pat[i], - *argval, - make_copy, - binding_mode); + bcx = bind_irrefutable_pat(bcx, sub_pat[i], + *argval, binding_mode); } } } @@ -1818,19 +1960,14 @@ pub fn bind_irrefutable_pat(bcx: block, let repr = adt::represent_node(bcx, pat.id); for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, - val, 0, i); - bcx = bind_irrefutable_pat(bcx, - *elem, - fldptr, - make_copy, - binding_mode); + val, 0, i); + bcx = bind_irrefutable_pat(bcx, *elem, + fldptr, binding_mode); } } } } Some(&ast::def_static(_, false)) => { - bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, - binding_mode); } _ => { // Nothing to do here. @@ -1845,12 +1982,8 @@ pub fn bind_irrefutable_pat(bcx: block, for fields.iter().advance |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); let fldptr = adt::trans_field_ptr(bcx, pat_repr, val, - discr, ix); - bcx = bind_irrefutable_pat(bcx, - f.pat, - fldptr, - make_copy, - binding_mode); + discr, ix); + bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode); } } } @@ -1858,11 +1991,7 @@ pub fn bind_irrefutable_pat(bcx: block, let repr = adt::represent_node(bcx, pat.id); for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); - bcx = bind_irrefutable_pat(bcx, - *elem, - fldptr, - make_copy, - binding_mode); + bcx = bind_irrefutable_pat(bcx, *elem, fldptr, binding_mode); } } ast::pat_box(inner) | ast::pat_uniq(inner) => { @@ -1872,22 +2001,30 @@ pub fn bind_irrefutable_pat(bcx: block, ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox, _ => GEPi(bcx, llbox, [0u, abi::box_field_body]) }; - bcx = bind_irrefutable_pat(bcx, - inner, - unboxed, - true, - binding_mode); + bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode); } ast::pat_region(inner) => { let loaded_val = Load(bcx, val); - bcx = bind_irrefutable_pat(bcx, - inner, - loaded_val, - true, - binding_mode); - } - ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) | - ast::pat_vec(*) => () + bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode); + } + ast::pat_vec(*) => { + bcx.tcx().sess.span_bug( + pat.span, + fmt!("vector patterns are never irrefutable!")); + } + ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => () } return bcx; } + +fn simple_identifier<'a>(pat: &'a ast::pat) -> Option<&'a ast::Path> { + match pat.node { + ast::pat_ident(ast::bind_infer, ref path, None) => { + Some(path) + } + _ => { + None + } + } +} + diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 577f1c6896067..80fc3803ae732 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -59,6 +59,7 @@ use middle::trans::type_of::*; use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; +use middle::pat_util; use middle::trans::type_::Type; @@ -75,7 +76,7 @@ use extra::time; use extra::sort; use syntax::ast::ident; use syntax::ast_map::{path, path_elt_to_str, path_name}; -use syntax::ast_util::{local_def, path_to_ident}; +use syntax::ast_util::{local_def}; use syntax::attr; use syntax::codemap::span; use syntax::parse::token; @@ -111,8 +112,8 @@ impl Drop for _InsnCtxt { fn drop(&self) { unsafe { do local_data::local_data_modify(task_local_insn_key) |c| { - do c.map_consume |@ctx| { - let mut ctx = ctx; + do c.map_consume |ctx| { + let mut ctx = copy *ctx; ctx.pop(); @ctx } @@ -125,8 +126,8 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: %s", s); unsafe { do local_data::local_data_modify(task_local_insn_key) |c| { - do c.map_consume |@ctx| { - let mut ctx = ctx; + do c.map_consume |ctx| { + let mut ctx = copy *ctx; ctx.push(s); @ctx } @@ -1012,7 +1013,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { match bcx.fcx.personality { Some(addr) => Store(pad_bcx, llretval, addr), None => { - let addr = alloca(pad_bcx, val_ty(llretval)); + let addr = alloca(pad_bcx, val_ty(llretval), ""); bcx.fcx.personality = Some(addr); Store(pad_bcx, llretval, addr); } @@ -1056,7 +1057,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { if ty::type_is_bot(t) { return C_null(Type::i8p()); } - let llptr = alloc_ty(bcx, t); + let llptr = alloc_ty(bcx, t, ""); Store(bcx, v, llptr); return llptr; } @@ -1064,7 +1065,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { // Since this function does *not* root, it is the caller's responsibility to // ensure that the referent is pointed to by a root. pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef { - let llptr = alloca(cx, val_ty(v)); + let llptr = alloca(cx, val_ty(v), ""); Store(cx, v, llptr); return llptr; } @@ -1121,9 +1122,6 @@ pub fn init_local(bcx: block, local: &ast::local) -> block { let _indenter = indenter(); let _icx = push_ctxt("init_local"); - let ty = node_id_type(bcx, local.node.id); - - debug!("ty=%s", bcx.ty_to_str(ty)); if ignore_lhs(bcx, local) { // Handle let _ = e; just like e; @@ -1135,36 +1133,7 @@ pub fn init_local(bcx: block, local: &ast::local) -> block { } } - let llptr = match bcx.fcx.lllocals.find_copy(&local.node.id) { - Some(v) => v, - _ => { - 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!"); - } - }; - - let mut bcx = bcx; - match local.node.init { - Some(init) => { - bcx = expr::trans_into(bcx, init, expr::SaveIn(llptr)); - } - _ => { - zero_mem(bcx, llptr, ty); - } - } - - // Make a note to drop this slot on the way out. - debug!("adding clean for %?/%s to bcx=%s", - local.node.id, bcx.ty_to_str(ty), - bcx.to_str()); - add_clean(bcx, llptr, ty); - - return _match::bind_irrefutable_pat(bcx, - local.node.pat, - llptr, - false, - _match::BindLocal); + _match::store_local(bcx, local.node.pat, local.node.init) } pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { @@ -1469,28 +1438,6 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { } } -pub fn alloc_local(cx: block, local: &ast::local) -> block { - let _icx = push_ctxt("alloc_local"); - let t = node_id_type(cx, local.node.id); - let simple_name = match local.node.pat.node { - ast::pat_ident(_, ref pth, None) => Some(path_to_ident(pth)), - _ => None - }; - let val = alloc_ty(cx, t); - if cx.sess().opts.debuginfo { - for simple_name.iter().advance |name| { - str::as_c_str(cx.ccx().sess.str_of(*name), |buf| { - unsafe { - llvm::LLVMSetValueName(val, buf) - } - }); - } - } - cx.fcx.lllocals.insert(local.node.id, val); - cx -} - - pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { let _icx = push_ctxt("with_cond"); let next_cx = base::sub_block(bcx, "next"); @@ -1561,20 +1508,20 @@ pub fn memzero(cx: block, llptr: ValueRef, ty: Type) { Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]); } -pub fn alloc_ty(bcx: block, t: ty::t) -> ValueRef { +pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef { let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); assert!(!ty::type_has_params(t), "Type has params: %s", ty_to_str(ccx.tcx, t)); - let val = alloca(bcx, ty); + let val = alloca(bcx, ty, name); return val; } -pub fn alloca(cx: block, ty: Type) -> ValueRef { - alloca_maybe_zeroed(cx, ty, false) +pub fn alloca(cx: block, ty: Type, name: &str) -> ValueRef { + alloca_maybe_zeroed(cx, ty, name, false) } -pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef { +pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> ValueRef { let _icx = push_ctxt("alloca"); if cx.unreachable { unsafe { @@ -1582,7 +1529,7 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef { } } let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas); - let p = Alloca(initcx, ty); + let p = Alloca(initcx, ty, name); if zero { memzero(initcx, p, ty); } p } @@ -1623,7 +1570,8 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef { llvm::LLVMGetParam(fcx.llfn, 0) } else { let lloutputtype = type_of::type_of(fcx.ccx, output_type); - alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype) + alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype, + "__make_return_pointer") } } } @@ -1738,6 +1686,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt, let arg = &args[i]; let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint); + // FIXME #7260: aliasing should be determined by monomorphized ty::t match arg.ty.node { // `~` pointers never alias other parameters, because ownership was transferred ast::ty_uniq(_) => { @@ -1766,7 +1715,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, let self_val = if slf.is_copy && datum::appropriate_mode(bcx.tcx(), slf.t).is_by_value() { let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t)); - let alloc = alloc_ty(bcx, slf.t); + let alloc = alloc_ty(bcx, slf.t, "__self"); Store(bcx, tmp, alloc); alloc } else { @@ -1782,7 +1731,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, for uint::range(0, arg_tys.len()) |arg_n| { let arg_ty = arg_tys[arg_n]; let raw_llarg = raw_llargs[arg_n]; - let arg_id = args[arg_n].id; // For certain mode/type combinations, the raw llarg values are passed // by value. However, within the fn body itself, we want to always @@ -1793,22 +1741,13 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, // the event it's not truly needed. // only by value if immediate: let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() { - let alloc = alloc_ty(bcx, arg_ty); + let alloc = alloc_ty(bcx, arg_ty, "__arg"); Store(bcx, raw_llarg, alloc); alloc } else { raw_llarg }; - - add_clean(bcx, llarg, arg_ty); - - bcx = _match::bind_irrefutable_pat(bcx, - args[arg_n].pat, - llarg, - false, - _match::BindArgument); - - fcx.llargs.insert(arg_id, llarg); + bcx = _match::store_arg(bcx, args[arg_n].pat, llarg); if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span); @@ -1967,81 +1906,51 @@ pub fn trans_fn(ccx: @mut CrateContext, |_bcx| { }); } +fn insert_synthetic_type_entries(bcx: block, + fn_args: &[ast::arg], + arg_tys: &[ty::t]) +{ + /*! + * For tuple-like structs and enum-variants, we generate + * synthetic AST nodes for the arguments. These have no types + * in the type table and no entries in the moves table, + * so the code in `copy_args_to_allocas` and `bind_irrefutable_pat` + * gets upset. This hack of a function bridges the gap by inserting types. + * + * This feels horrible. I think we should just have a special path + * for these functions and not try to use the generic code, but + * that's not the problem I'm trying to solve right now. - nmatsakis + */ + + let tcx = bcx.tcx(); + for uint::range(0, fn_args.len()) |i| { + debug!("setting type of argument %u (pat node %d) to %s", + i, fn_args[i].pat.id, bcx.ty_to_str(arg_tys[i])); + + let pat_id = fn_args[i].pat.id; + let arg_ty = arg_tys[i]; + tcx.node_types.insert(pat_id as uint, arg_ty); + } +} + pub fn trans_enum_variant(ccx: @mut CrateContext, - enum_id: ast::node_id, + _enum_id: ast::node_id, variant: &ast::variant, args: &[ast::variant_arg], disr: int, param_substs: Option<@param_substs>, llfndecl: ValueRef) { let _icx = push_ctxt("trans_enum_variant"); - // Translate variant arguments to function arguments. - let fn_args = do args.map |varg| { - ast::arg { - is_mutbl: false, - ty: copy varg.ty, - pat: ast_util::ident_to_pat( - ccx.tcx.sess.next_node_id(), - codemap::dummy_sp(), - special_idents::arg), - id: varg.id, - } - }; - - let ty_param_substs = match param_substs { - Some(ref substs) => { copy substs.tys } - None => ~[] - }; - let enum_ty = ty::subst_tps(ccx.tcx, - ty_param_substs, - None, - ty::node_id_to_type(ccx.tcx, enum_id)); - let fcx = new_fn_ctxt_w_id(ccx, - ~[], - llfndecl, - variant.node.id, - enum_ty, - param_substs, - None); - - let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; - let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id)); - let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); - - // XXX is there a better way to reconstruct the ty::t? - let repr = adt::represent_type(ccx, enum_ty); - - debug!("trans_enum_variant: name=%s tps=%s repr=%? enum_ty=%s", - unsafe { str::raw::from_c_str(llvm::LLVMGetValueName(llfndecl)) }, - ~"[" + ty_param_substs.map(|&t| ty_to_str(ccx.tcx, t)).connect(", ") + "]", - repr, ty_to_str(ccx.tcx, enum_ty)); - adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); - for args.iter().enumerate().advance |(i, va)| { - let lldestptr = adt::trans_field_ptr(bcx, - repr, - fcx.llretptr.get(), - disr, - i); - - // If this argument to this function is a enum, it'll have come in to - // this function as an opaque blob due to the way that type_of() - // works. So we have to cast to the destination's view of the type. - let llarg = match fcx.llargs.find(&va.id) { - Some(&x) => x, - _ => fail!("trans_enum_variant: how do we know this works?"), - }; - let arg_ty = arg_tys[i]; - memcpy_ty(bcx, lldestptr, llarg, arg_ty); - } - build_return(bcx); - finish_fn(fcx, lltop); + trans_enum_variant_or_tuple_like_struct( + ccx, + variant.node.id, + args, + disr, + param_substs, + llfndecl); } -// NB: In theory this should be merged with the function above. But the AST -// structures are completely different, so very little code would be shared. pub fn trans_tuple_struct(ccx: @mut CrateContext, fields: &[@ast::struct_field], ctor_id: ast::node_id, @@ -2049,37 +1958,72 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, llfndecl: ValueRef) { let _icx = push_ctxt("trans_tuple_struct"); - // Translate struct fields to function arguments. - let fn_args = do fields.map |field| { + trans_enum_variant_or_tuple_like_struct( + ccx, + ctor_id, + fields, + 0, + param_substs, + llfndecl); +} + +trait IdAndTy { + fn id(&self) -> ast::node_id; + fn ty<'a>(&'a self) -> &'a ast::Ty; +} + +impl IdAndTy for ast::variant_arg { + fn id(&self) -> ast::node_id { self.id } + fn ty<'a>(&'a self) -> &'a ast::Ty { &self.ty } +} + +impl IdAndTy for @ast::struct_field { + fn id(&self) -> ast::node_id { self.node.id } + fn ty<'a>(&'a self) -> &'a ast::Ty { &self.node.ty } +} + +pub fn trans_enum_variant_or_tuple_like_struct( + ccx: @mut CrateContext, + ctor_id: ast::node_id, + args: &[A], + disr: int, + param_substs: Option<@param_substs>, + llfndecl: ValueRef) +{ + // Translate variant arguments to function arguments. + let fn_args = do args.map |varg| { ast::arg { is_mutbl: false, - ty: copy field.node.ty, - pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(), - codemap::dummy_sp(), - special_idents::arg), - id: field.node.id + ty: copy *varg.ty(), + pat: ast_util::ident_to_pat( + ccx.tcx.sess.next_node_id(), + codemap::dummy_sp(), + special_idents::arg), + id: varg.id(), } }; - // XXX is there a better way to reconstruct the ty::t? let ty_param_substs = match param_substs { Some(ref substs) => { copy substs.tys } None => ~[] }; + let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None, ty::node_id_to_type(ccx.tcx, ctor_id)); - let tup_ty = match ty::get(ctor_ty).sty { + + let result_ty = match ty::get(ctor_ty).sty { ty::ty_bare_fn(ref bft) => bft.sig.output, - _ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \ - return type %s", - ty_to_str(ccx.tcx, ctor_ty))) + _ => ccx.sess.bug( + fmt!("trans_enum_variant_or_tuple_like_struct: \ + unexpected ctor return type %s", + ty_to_str(ccx.tcx, ctor_ty))) }; let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, - tup_ty, + result_ty, param_substs, None); @@ -2087,23 +2031,23 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, let bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; - let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id)); - let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); + let arg_tys = ty::ty_fn_args(ctor_ty); - let repr = adt::represent_type(ccx, tup_ty); - adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0); + insert_synthetic_type_entries(bcx, fn_args, arg_tys); + let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); - for fields.iter().enumerate().advance |(i, field)| { + let repr = adt::represent_type(ccx, result_ty); + adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); + for fn_args.iter().enumerate().advance |(i, fn_arg)| { let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr.get(), - 0, + disr, i); - let llarg = fcx.llargs.get_copy(&field.node.id); + let llarg = fcx.llargs.get_copy(&fn_arg.pat.id); let arg_ty = arg_tys[i]; memcpy_ty(bcx, lldestptr, llarg, arg_ty); } - build_return(bcx); finish_fn(fcx, lltop); } @@ -3033,13 +2977,17 @@ pub fn trans_crate(sess: session::Session, do sort::quick_sort(ccx.stats.fn_stats) |&(_, _, insns_a), &(_, _, insns_b)| { insns_a > insns_b } - for ccx.stats.fn_stats.iter().advance |&(name, ms, insns)| { - io::println(fmt!("%u insns, %u ms, %s", insns, ms, name)); + for ccx.stats.fn_stats.iter().advance |tuple| { + match *tuple { + (ref name, ms, insns) => { + io::println(fmt!("%u insns, %u ms, %s", insns, ms, *name)); + } + } } } if ccx.sess.count_llvm_insns() { - for ccx.stats.llvm_insns.iter().advance |(&k, &v)| { - io::println(fmt!("%-7u %s", v, k)); + for ccx.stats.llvm_insns.iter().advance |(k, v)| { + io::println(fmt!("%-7u %s", *v, *k)); } } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index b62b73423e9b1..db5553ca939d7 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -505,11 +505,17 @@ pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { } } -pub fn Alloca(cx: block, Ty: Type) -> ValueRef { +pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef { unsafe { if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } count_insn(cx, "alloca"); - return llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname()); + if name.is_empty() { + llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname()) + } else { + str::as_c_str( + name, + |c| llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), c)) + } } } diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index d00479194308b..8d741369e1a25 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -130,10 +130,10 @@ impl FnType { j = 1u; get_param(llwrapfn, 0u) } else if self.ret_ty.cast { - let retptr = alloca(bcx, self.ret_ty.ty); + let retptr = alloca(bcx, self.ret_ty.ty, ""); BitCast(bcx, retptr, ret_ty.ptr_to()) } else { - alloca(bcx, ret_ty) + alloca(bcx, ret_ty, "") }; let mut i = 0u; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 473afda48e65d..22adc4aa24b65 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -600,7 +600,7 @@ pub fn trans_call_inner(in_cx: block, let mut bcx = callee.bcx; let ccx = cx.ccx(); let ret_flag = if ret_in_loop { - let flag = alloca(bcx, Type::bool()); + let flag = alloca(bcx, Type::bool(), "__ret_flag"); Store(bcx, C_bool(false), flag); Some(flag) } else { @@ -675,7 +675,7 @@ pub fn trans_call_inner(in_cx: block, unsafe { if ty::type_needs_drop(bcx.tcx(), ret_ty) { if ty::type_is_immediate(bcx.tcx(), ret_ty) { - let llscratchptr = alloc_ty(bcx, ret_ty); + let llscratchptr = alloc_ty(bcx, ret_ty, "__ret"); Store(bcx, llresult, llscratchptr); bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); } else { @@ -733,7 +733,7 @@ pub fn trans_ret_slot(bcx: block, fn_ty: ty::t, dest: Option) llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()) } } else { - alloc_ty(bcx, retty) + alloc_ty(bcx, retty, "__trans_ret_slot") } } } @@ -823,7 +823,7 @@ pub fn trans_arg_expr(bcx: block, _ }) => { let scratch_ty = expr_ty(bcx, arg_expr); - let scratch = alloc_ty(bcx, scratch_ty); + let scratch = alloc_ty(bcx, scratch_ty, "__ret_flag"); let arg_ty = expr_ty(bcx, arg_expr); let sigil = ty::ty_closure_sigil(arg_ty); let bcx = closure::trans_expr_fn( @@ -860,8 +860,6 @@ pub fn trans_arg_expr(bcx: block, // FIXME(#3548) use the adjustments table match autoref_arg { DoAutorefArg => { - assert!(! - bcx.ccx().maps.moves_map.contains(&arg_expr.id)); val = arg_datum.to_ref_llval(bcx); } DontAutorefArg => { @@ -875,10 +873,10 @@ pub fn trans_arg_expr(bcx: block, // &arg_expr.id); debug!("by ref arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); - let scratch = scratch_datum(bcx, arg_datum.ty, false); + let scratch = scratch_datum(bcx, arg_datum.ty, + "__self", false); arg_datum.store_to_datum(bcx, - arg_expr.id, INIT, scratch); @@ -895,10 +893,10 @@ pub fn trans_arg_expr(bcx: block, arg_datum.appropriate_mode(bcx.tcx()).is_by_ref() { debug!("by copy arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); - let scratch = scratch_datum(bcx, arg_datum.ty, false); + let scratch = scratch_datum(bcx, arg_datum.ty, + "__arg", false); arg_datum.store_to_datum(bcx, - arg_expr.id, INIT, scratch); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 4c63b8dc84451..5b0212cc05cc7 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -193,7 +193,7 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) } ast::BorrowedSigil => { let cbox_ty = tuplify_box_ty(tcx, cdata_ty); - let llbox = alloc_ty(bcx, cbox_ty); + let llbox = alloc_ty(bcx, cbox_ty, "__closure"); nuke_ref_count(bcx, llbox); rslt(bcx, llbox) } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 973a124c48ad2..24648ada8935e 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -608,6 +608,10 @@ impl block_ { pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx } pub fn sess(&self) -> Session { self.fcx.ccx.sess } + pub fn ident(&self, ident: ident) -> @str { + token::ident_to_str(&ident) + } + pub fn node_id_to_str(&self, id: ast::node_id) -> ~str { ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr()) } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index ebaa317944284..2880c68c1e036 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -96,7 +96,7 @@ pub struct CrateContext { all_llvm_symbols: HashSet<@str>, tcx: ty::ctxt, maps: astencode::Maps, - stats: Stats, + stats: @mut Stats, upcalls: @upcall::Upcalls, tydesc_type: Type, int_type: Type, @@ -201,7 +201,7 @@ impl CrateContext { all_llvm_symbols: HashSet::new(), tcx: tcx, maps: maps, - stats: Stats { + stats: @mut Stats { n_static_tydescs: 0u, n_glues_created: 0u, n_null_glues: 0u, diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 8ca4253ead8b8..904e6e14e28db 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -35,9 +35,6 @@ use syntax::codemap::span; pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block { let _icx = push_ctxt("trans_block"); let mut bcx = bcx; - do block_locals(b) |local| { - bcx = alloc_local(bcx, local); - }; for b.node.stmts.iter().advance |s| { debuginfo::update_source_pos(bcx, b.span); bcx = trans_stmt(bcx, *s); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index e86709d72b329..1de619433afbd 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -70,8 +70,8 @@ * This is a "shallow" clone. After `move_to()`, the current datum * is invalid and should no longer be used. * - * - `store_to()` either performs a copy or a move by consulting the - * moves_map computed by `middle::moves`. + * - `store_to()` either performs a copy or a move depending on the + * Rust type of the datum. * * # Scratch datum * @@ -173,19 +173,19 @@ pub fn immediate_rvalue_bcx(bcx: block, return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)}; } -pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum { +pub fn scratch_datum(bcx: block, ty: ty::t, name: &str, zero: bool) -> Datum { /*! - * * Allocates temporary space on the stack using alloca() and * returns a by-ref Datum pointing to it. If `zero` is true, the * space will be zeroed when it is allocated; this is normally not * necessary, but in the case of automatic rooting in match * statements it is possible to have temporaries that may not get * initialized if a certain arm is not taken, so we must zero - * them. You must arrange any cleanups etc yourself! */ + * them. You must arrange any cleanups etc yourself! + */ let llty = type_of::type_of(bcx.ccx(), ty); - let scratch = alloca_maybe_zeroed(bcx, llty, zero); + let scratch = alloca_maybe_zeroed(bcx, llty, name, zero); Datum { val: scratch, ty: ty, mode: ByRef(RevokeClean) } } @@ -208,7 +208,6 @@ pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode { impl Datum { pub fn store_to(&self, bcx: block, - id: ast::node_id, action: CopyAction, dst: ValueRef) -> block { @@ -218,7 +217,7 @@ impl Datum { * `id` is located in the move table, but copies otherwise. */ - if bcx.ccx().maps.moves_map.contains(&id) { + if ty::type_moves_by_default(bcx.tcx(), self.ty) { self.move_to(bcx, action, dst) } else { self.copy_to(bcx, action, dst) @@ -227,7 +226,6 @@ impl Datum { pub fn store_to_dest(&self, bcx: block, - id: ast::node_id, dest: expr::Dest) -> block { match dest { @@ -235,21 +233,20 @@ impl Datum { return bcx; } expr::SaveIn(addr) => { - return self.store_to(bcx, id, INIT, addr); + return self.store_to(bcx, INIT, addr); } } } pub fn store_to_datum(&self, bcx: block, - id: ast::node_id, action: CopyAction, datum: Datum) -> block { debug!("store_to_datum(self=%s, action=%?, datum=%s)", self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx())); assert!(datum.mode.is_by_ref()); - self.store_to(bcx, id, action, datum.val) + self.store_to(bcx, action, datum.val) } pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum) @@ -476,7 +473,7 @@ impl Datum { if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to()) } else { - let slot = alloc_ty(bcx, self.ty); + let slot = alloc_ty(bcx, self.ty, ""); Store(bcx, self.val, slot); slot } @@ -828,11 +825,10 @@ impl DatumBlock { } pub fn store_to(&self, - id: ast::node_id, action: CopyAction, dst: ValueRef) -> block { - self.datum.store_to(self.bcx, id, action, dst) + self.datum.store_to(self.bcx, action, dst) } pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 0180eeb3d2205..19a0f7262ff6e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -23,7 +23,8 @@ This will generate code that evaluates `expr`, storing the result into `Dest`, which must either be the special flag ignore (throw the result away) or be a pointer to memory of the same type/size as the expression. It returns the resulting basic block. This form will -handle all automatic adjustments and moves for you. +handle all automatic adjustments for you. The value will be moved if +its type is linear and copied otherwise. ## Translation to a datum @@ -42,18 +43,18 @@ This function generates code to evaluate the expression and return a tries to return its result in the most efficient way possible, without introducing extra copies or sacrificing information. Therefore, for lvalue expressions, you always get a by-ref `Datum` in return that -points at the memory for this lvalue (almost, see [1]). For rvalue -expressions, we will return a by-value `Datum` whenever possible, but -it is often necessary to allocate a stack slot, store the result of -the rvalue in there, and then return a pointer to the slot (see the -discussion later on about the different kinds of rvalues). +points at the memory for this lvalue. For rvalue expressions, we will +return a by-value `Datum` whenever possible, but it is often necessary +to allocate a stack slot, store the result of the rvalue in there, and +then return a pointer to the slot (see the discussion later on about +the different kinds of rvalues). NB: The `trans_to_datum()` function does perform adjustments, but since it returns a pointer to the value "in place" it does not handle -any moves that may be relevant. If you are transing an expression -whose result should be moved, you should either use the Datum methods -`move_to()` (for unconditional moves) or `store_to()` (for moves -conditioned on the type of the expression) at some point. +moves. If you wish to copy/move the value returned into a new +location, you should use the Datum method `store_to()` (move or copy +depending on type). You can also use `move_to()` (force move) or +`copy_to()` (force copy) for special situations. ## Translating local variables @@ -110,13 +111,6 @@ generate phi nodes). Finally, statement rvalues are rvalues that always produce a nil return type, such as `while` loops or assignments (`a = b`). -## Caveats - -[1] Actually, some lvalues are only stored by value and not by -reference. An example (as of this writing) would be immutable -arguments or pattern bindings of immediate type. However, mutable -lvalues are *never* stored by value. - */ @@ -274,7 +268,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { ty::mt { ty: unit_ty, mutbl: ast::m_imm }, ty::vstore_slice(ty::re_static)); - let scratch = scratch_datum(bcx, slice_ty, false); + let scratch = scratch_datum(bcx, slice_ty, "__adjust", false); Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock {bcx: bcx, datum: scratch} @@ -290,7 +284,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let closure_ty = expr_ty_adjusted(bcx, expr); debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx)); - let scratch = scratch_datum(bcx, closure_ty, false); + let scratch = scratch_datum(bcx, closure_ty, "__adjust", false); let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); assert_eq!(datum.appropriate_mode(tcx), ByValue); Store(bcx, datum.to_appropriate_llval(bcx), llfn); @@ -315,7 +309,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { let datumblock = trans_to_datum(bcx, expr); return match dest { Ignore => datumblock.bcx, - SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest) + SaveIn(lldest) => datumblock.store_to(INIT, lldest) }; } @@ -343,7 +337,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { let datumblock = trans_lvalue_unadjusted(bcx, expr); match dest { Ignore => datumblock.bcx, - SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest) + SaveIn(lldest) => datumblock.store_to(INIT, lldest) } } ty::RvalueDatumExpr => { @@ -351,8 +345,9 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { match dest { Ignore => datumblock.drop_val(), - // NB: We always do `move_to()` regardless of the - // moves_map because we're processing an rvalue + // When processing an rvalue, the value will be newly + // allocated, so we always `move_to` so as not to + // unnecessarily inc ref counts and so forth: SaveIn(lldest) => datumblock.move_to(INIT, lldest) } } @@ -386,11 +381,11 @@ fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock { fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { /*! - * * Translates an expression into a datum. If this expression * is an rvalue, this will result in a temporary value being - * created. If you already know where the result should be stored, - * you should use `trans_into()` instead. */ + * created. If you plan to store the value somewhere else, + * you should prefer `trans_into()` instead. + */ let mut bcx = bcx; @@ -423,7 +418,7 @@ fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore); return nil(bcx, ty); } else { - let scratch = scratch_datum(bcx, ty, false); + let scratch = scratch_datum(bcx, ty, "", false); bcx = trans_rvalue_dps_unadjusted( bcx, expr, SaveIn(scratch.val)); @@ -535,7 +530,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { let dst_datum = unpack_datum!( bcx, trans_lvalue(bcx, dst)); return src_datum.store_to_datum( - bcx, src.id, DROP_EXISTING, dst_datum); + bcx, DROP_EXISTING, dst_datum); } ast::expr_assign_op(callee_id, op, dst, src) => { return trans_assign_op(bcx, expr, callee_id, op, dst, src); @@ -638,7 +633,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, return trans_into(bcx, blk, dest); } ast::expr_copy(a) => { - return trans_into(bcx, a, dest); + // If we just called `trans_into(bcx, a, dest)`, then this + // might *move* the value into `dest` if the value is + // non-copyable. So first get a datum and then do an + // explicit copy. + let datumblk = trans_to_datum(bcx, a); + return match dest { + Ignore => datumblk.bcx, + SaveIn(llval) => datumblk.copy_to(INIT, llval) + }; } ast::expr_call(f, ref args, _) => { return callee::trans_call( @@ -1221,6 +1224,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, bcx = trans_into(bcx, e, Ignore); } for optbase.iter().advance |sbi| { + // FIXME #7261: this moves entire base, not just certain fields bcx = trans_into(bcx, sbi.expr, Ignore); } return bcx; @@ -1245,7 +1249,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, adt::trans_field_ptr(bcx, repr, srcval, discr, i) }; let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); - bcx = datum.store_to(bcx, base.expr.id, INIT, dest); + bcx = datum.store_to(bcx, INIT, dest); } } @@ -1687,7 +1691,7 @@ fn trans_assign_op(bcx: block, // A user-defined operator method if bcx.ccx().maps.method_map.find(&expr.id).is_some() { // FIXME(#2528) evaluates the receiver twice!! - let scratch = scratch_datum(bcx, dst_datum.ty, false); + let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false); let bcx = trans_overloaded_op(bcx, expr, callee_id, diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 2c505853d5eb7..bdae222059894 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -195,14 +195,15 @@ fn build_wrap_fn_(ccx: @mut CrateContext, if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) { let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output); fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas), - lloutputtype)); + lloutputtype, + "")); } let bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; // Allocate the struct and write the arguments into it. - let llargbundle = alloca(bcx, tys.bundle_ty); + let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle"); arg_builder(bcx, tys, llwrapfn, llargbundle); // Create call itself. @@ -732,7 +733,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let llsrcval = get_param(decl, first_real_arg); let llsrcptr = if ty::type_is_immediate(ccx.tcx, in_type) { - let llsrcptr = alloca(bcx, llintype); + let llsrcptr = alloca(bcx, llintype, "__llsrcptr"); Store(bcx, llsrcval, llsrcptr); llsrcptr } else { diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index bc493bfa23ec3..25e73fd640d43 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -132,7 +132,7 @@ pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) | ty::ty_opaque_closure_ptr(_) => { - let vp = alloca(bcx, type_of(bcx.ccx(), t)); + let vp = alloca(bcx, type_of(bcx.ccx(), t), ""); Store(bcx, v, vp); free_ty(bcx, vp, t) } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 14cc822b5a571..0914e61d58f33 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -614,7 +614,8 @@ pub fn trans_trait_callee_from_llval(bcx: block, } llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to()); - let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false); + let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), + "__trait_callee", false); Store(bcx, llself, scratch.val); scratch.add_clean(bcx); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index cc4111aa1947d..a3b544dbc6195 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -57,7 +57,7 @@ impl Reflector { let bcx = self.bcx; let str_vstore = ty::vstore_slice(ty::re_static); let str_ty = ty::mk_estr(bcx.tcx(), str_vstore); - let scratch = scratch_datum(bcx, str_ty, false); + let scratch = scratch_datum(bcx, str_ty, "", false); let len = C_uint(bcx.ccx(), s.len() + 1); let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p()); Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ])); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 41dbe320d2d10..825320b9ff636 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -332,7 +332,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::e let llptrval = PointerCast(bcx, llptrval, Type::i8p()); let llsizeval = C_uint(bcx.ccx(), s.len()); let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq); - let lldestval = scratch_datum(bcx, typ, false); + let lldestval = scratch_datum(bcx, typ, "", false); let bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.strdup_uniq_fn(), @@ -454,7 +454,7 @@ pub fn write_content(bcx: block, let loop_counter = { // i = 0 - let i = alloca(loop_bcx, bcx.ccx().int_type); + let i = alloca(loop_bcx, bcx.ccx().int_type, "__i"); Store(loop_bcx, C_uint(bcx.ccx(), 0), i); Br(loop_bcx, cond_bcx.llbb); diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs index bd22e41aff8f0..1804a7334f23f 100644 --- a/src/librustc/middle/trans/write_guard.rs +++ b/src/librustc/middle/trans/write_guard.rs @@ -120,7 +120,7 @@ fn root(datum: &Datum, // First, root the datum. Note that we must zero this value, // because sometimes we root on one path but not another. // See e.g. #4904. - let scratch = scratch_datum(bcx, datum.ty, true); + let scratch = scratch_datum(bcx, datum.ty, "__write_guard", true); datum.copy_to_datum(bcx, INIT, scratch); let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); add_clean_temp_mem_in_scope(cleanup_bcx, root_info.scope, scratch.val, scratch.ty); @@ -135,7 +135,8 @@ fn root(datum: &Datum, // scratch.val will be NULL should the cleanup get // called without the freezing actually occurring, and // return_to_mut checks for this condition. - let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); + let scratch_bits = scratch_datum(bcx, ty::mk_uint(), + "__write_guard_bits", false); let freeze_did = match freeze_kind { DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 1f7946576db5c..ac7a9db99e9ac 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, None => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a structure pattern", None); fcx.write_error(pat.id); @@ -200,9 +200,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, _ => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"an enum or structure pattern", None); fcx.write_error(pat.id); @@ -534,9 +534,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { _ => ty::terr_mismatch }; fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + *e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); fcx.write_error(pat.id); } } @@ -583,9 +583,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.infcx().type_error_message_str_with_expected( pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a vector pattern", None); @@ -641,9 +641,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str_with_expected( span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index e5248e01ed796..d59c8e5e894fb 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -350,10 +350,7 @@ pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt, self_info.self_id); } for decl.inputs.iter().advance |arg| { - do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat) - |_bm, pat_id, span, _path| { - resolve_type_vars_for_node(wbcx, span, pat_id); - } + (visit.visit_pat)(arg.pat, (wbcx, visit)); // Privacy needs the type for the whole pattern, not just each binding if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) { resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id); diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 473d5b8e6e880..7ee731d4f46b4 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -209,7 +209,7 @@ impl CoherenceChecker { match item.node { item_impl(_, ref opt_trait, _, _) => { let opt_trait : ~[trait_ref] = opt_trait.iter() - .transform(|&x| x) + .transform(|x| copy *x) .collect(); self.check_implementation(item, opt_trait); } @@ -270,7 +270,7 @@ impl CoherenceChecker { // We only want to generate one Impl structure. When we generate one, // we store it here so that we don't recreate it. let mut implementation_opt = None; - for associated_traits.iter().advance |&associated_trait| { + for associated_traits.iter().advance |associated_trait| { let trait_ref = ty::node_id_to_trait_ref( self.crate_context.tcx, diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index b2f608bd352ae..54ad888e2ae8c 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -202,7 +202,7 @@ impl PkgSrc { crates: &[Crate], cfgs: &[~str], what: OutputType) { - for crates.iter().advance |&crate| { + for crates.iter().advance |crate| { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index b8f77ceececd7..c6f7735b204e4 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -71,8 +71,8 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); let dirs = os::list_dir(&src_dir); - for dirs.iter().advance |&p| { - let p = Path(p); + for dirs.iter().advance |p| { + let p = Path(copy *p); debug!("=> p = %s", p.to_str()); if !os::path_is_dir(&src_dir.push_rel(&p)) { loop; @@ -84,8 +84,8 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { } else { let pf = p.filename(); - for pf.iter().advance |&pf| { - let f_ = copy pf; + for pf.iter().advance |pf| { + let f_ = copy *pf; let g = f_.to_str(); match split_version_general(g, '-') { Some((ref might_match, ref vers)) => { @@ -217,10 +217,10 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); let mut result_filename = None; - for dir_contents.iter().advance |&p| { + for dir_contents.iter().advance |p| { let mut which = 0; let mut hash = None; - let p_path = Path(p); + let p_path = Path(copy *p); let extension = p_path.filetype(); debug!("p = %s, p's extension is %?", p.to_str(), extension); match extension { diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 900ef4896ca11..da5c98680b919 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -194,7 +194,7 @@ pub fn compile_input(ctxt: &Ctx, Main => ~[] } + flags - + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), + + cfgs.flat_map(|c| { ~[~"--cfg", copy *c] }), driver::optgroups()).get(); let options = @session::options { crate_type: crate_type, @@ -311,8 +311,8 @@ pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, what: OutputType) -> bool { debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); - for flags.iter().advance |&fl| { - debug!("+++ %s", fl); + for flags.iter().advance |fl| { + debug!("+++ %s", *fl); } compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) } diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index aee6f1bd204e3..2b42c085009df 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -142,6 +142,30 @@ pub unsafe fn set_memory(dst: *mut T, c: u8, count: uint) { memset64(dst, c, count as u64); } +/** + * Zeroes out `count * size_of::` bytes of memory at `dst` + */ +#[inline] +#[cfg(not(stage0))] +pub unsafe fn zero_memory(dst: *mut T, count: uint) { + set_memory(dst, 0, count); +} + +/** + * Zeroes out `count * size_of::` bytes of memory at `dst` + */ +#[inline] +#[cfg(stage0)] +pub unsafe fn zero_memory(dst: *mut T, count: uint) { + let mut count = count * sys::size_of::(); + let mut dst = dst as *mut u8; + while count > 0 { + *dst = 0; + dst = mut_offset(dst, 1); + count -= 1; + } +} + /** * Swap the values at two mutable locations of the same type, without * deinitialising or copying either one. @@ -172,6 +196,32 @@ pub unsafe fn replace_ptr(dest: *mut T, mut src: T) -> T { src } +/** + * Reads the value from `*src` and returns it. Does not copy `*src`. + */ +#[inline(always)] +pub unsafe fn read_ptr(src: *mut T) -> T { + let mut tmp: T = intrinsics::uninit(); + let t: *mut T = &mut tmp; + copy_memory(t, src, 1); + tmp +} + +/** + * Reads the value from `*src` and nulls it out. + * This currently prevents destructors from executing. + */ +#[inline(always)] +pub unsafe fn read_and_zero_ptr(dest: *mut T) -> T { + // Copy the data out from `dest`: + let tmp = read_ptr(dest); + + // Now zero out `dest`: + zero_memory(dest, 1); + + tmp +} + /// Transform a region pointer - &T - to an unsafe pointer - *T. #[inline] pub fn to_unsafe_ptr(thing: &T) -> *T { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 7e051b62171c8..17dc604a17858 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -715,10 +715,16 @@ fn with_envp(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T { let mut tmps = ~[]; let mut ptrs = ~[]; - for es.iter().advance |&(k, v)| { - let kv = @fmt!("%s=%s", k, v); - tmps.push(kv); - ptrs.push(str::as_c_str(*kv, |b| b)); + for es.iter().advance |pair| { + // Use of match here is just to workaround limitations + // in the stage0 irrefutable pattern impl. + match pair { + &(ref k, ref v) => { + let kv = @fmt!("%s=%s", *k, *v); + tmps.push(kv); + ptrs.push(str::as_c_str(*kv, |b| b)); + } + } } ptrs.push(ptr::null()); @@ -738,8 +744,8 @@ fn with_envp(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T { match env { Some(es) => { let mut blk = ~[]; - for es.iter().advance |&(k, v)| { - let kv = fmt!("%s=%s", k, v); + for es.iter().advance |pair| { + let kv = fmt!("%s=%s", pair.first(), pair.second()); blk.push_all(kv.as_bytes_with_null_consume()); } blk.push(0); @@ -1294,9 +1300,9 @@ mod tests { let output = str::from_bytes(prog.finish_with_output().output); let r = os::env(); - for r.iter().advance |&(k, v)| { + for r.iter().advance |&(ref k, ref v)| { // don't check windows magical empty-named variables - assert!(k.is_empty() || output.contains(fmt!("%s=%s", k, v))); + assert!(k.is_empty() || output.contains(fmt!("%s=%s", *k, *v))); } } #[test] diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 33857556548fa..a69ffca026b86 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -281,16 +281,16 @@ pub trait VectorVector { impl<'self, T:Copy> VectorVector for &'self [~[T]] { /// Flattens a vector of slices of T into a single vector of T. pub fn concat_vec(&self) -> ~[T] { - self.flat_map(|&inner| inner) + self.flat_map(|inner| copy *inner) } /// Concatenate a vector of vectors, placing a given separator between each. pub fn connect_vec(&self, sep: &T) -> ~[T] { let mut r = ~[]; let mut first = true; - for self.iter().advance |&inner| { + for self.iter().advance |inner| { if first { first = false; } else { r.push(copy *sep); } - r.push_all(inner); + r.push_all(copy *inner); } r } @@ -1256,16 +1256,15 @@ impl OwnedVector for ~[T] { /// ~~~ #[inline] fn push_all_move(&mut self, mut rhs: ~[T]) { - let new_len = self.len() + rhs.len(); + let self_len = self.len(); + let rhs_len = rhs.len(); + let new_len = self_len + rhs_len; self.reserve(new_len); - unsafe { - do rhs.as_mut_buf |p, len| { - for uint::range(0, len) |i| { - let x = ptr::replace_ptr(ptr::mut_offset(p, i), - intrinsics::uninit()); - self.push(x); - } - } + unsafe { // Note: infallible. + let self_p = vec::raw::to_mut_ptr(*self); + let rhs_p = vec::raw::to_ptr(rhs); + ptr::copy_memory(ptr::mut_offset(self_p, self_len), rhs_p, rhs_len); + raw::set_len(self, new_len); raw::set_len(&mut rhs, 0); } } @@ -1277,9 +1276,8 @@ impl OwnedVector for ~[T] { ln => { let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); unsafe { - let val = ptr::replace_ptr(valptr, intrinsics::init()); raw::set_len(self, ln - 1u); - Some(val) + Some(ptr::read_ptr(valptr)) } } } @@ -1410,7 +1408,7 @@ impl OwnedVector for ~[T] { unsafe { // This loop is optimized out for non-drop types. for uint::range(newlen, oldlen) |i| { - ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + ptr::read_and_zero_ptr(ptr::mut_offset(p, i)); } } } @@ -1555,37 +1553,93 @@ pub trait OwnedEqVector { impl OwnedEqVector for ~[T] { /** - * Remove consecutive repeated elements from a vector; if the vector is - * sorted, this removes all duplicates. - */ + * Remove consecutive repeated elements from a vector; if the vector is + * sorted, this removes all duplicates. + */ pub fn dedup(&mut self) { unsafe { - if self.len() == 0 { return; } - let mut last_written = 0; - let mut next_to_read = 1; - do self.as_mut_buf |p, ln| { - // last_written < next_to_read <= ln - while next_to_read < ln { - // last_written < next_to_read < ln - if *ptr::mut_offset(p, next_to_read) == - *ptr::mut_offset(p, last_written) { - ptr::replace_ptr(ptr::mut_offset(p, next_to_read), - intrinsics::uninit()); - } else { - last_written += 1; - // last_written <= next_to_read < ln - if next_to_read != last_written { - ptr::swap_ptr(ptr::mut_offset(p, last_written), - ptr::mut_offset(p, next_to_read)); - } + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. There exists the possibility that this + // vector is contained with an `@mut` box and hence is still + // readable by the outside world during the `Eq` comparisons. + // Moreover, those comparisons could fail, so we must ensure + // that the vector is in a valid state at all time. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then truncate the + // vector. This operation is still O(n). + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write`. + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], tis is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of vec. Truncate to w. + + let ln = self.len(); + if ln < 1 { return; } + + // Avoid bounds checks by using unsafe pointers. + let p = vec::raw::to_mut_ptr(*self); + let mut r = 1; + let mut w = 1; + + while r < ln { + let p_r = ptr::mut_offset(p, r); + let p_wm1 = ptr::mut_offset(p, w - 1); + if *p_r != *p_wm1 { + if r != w { + let p_w = ptr::mut_offset(p_wm1, 1); + util::swap(&mut *p_r, &mut *p_w); } - // last_written <= next_to_read < ln - next_to_read += 1; - // last_written < next_to_read <= ln + w += 1; } + r += 1; } - // last_written < next_to_read == ln - raw::set_len(self, last_written + 1); + + self.truncate(w); } } } diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 01769482d0829..3bc16477c808a 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -519,8 +519,8 @@ impl<'self> MethodDef<'self> { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); - let args = do arg_types.map |&(id, ty)| { - cx.arg(span, id, ty) + let args = do arg_types.map |pair| { + cx.arg(span, pair.first(), pair.second()) }; let ret_type = self.get_ret_ty(cx, span, generics, type_ident); @@ -589,7 +589,7 @@ impl<'self> MethodDef<'self> { // transpose raw_fields let fields = match raw_fields { - [self_arg, .. rest] => { + [ref self_arg, .. rest] => { do self_arg.iter().enumerate().transform |(i, &(opt_id, field))| { let other_fields = do rest.map |l| { match &l[i] { @@ -738,16 +738,20 @@ impl<'self> MethodDef<'self> { let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]); - for matches_so_far.tail().iter().advance |&(_, _, other_fields)| { - for other_fields.iter().enumerate().advance |(i, &(_, other_field))| { - enum_matching_fields[i].push(other_field); + for matches_so_far.tail().iter().advance |triple| { + match triple { + &(_, _, ref other_fields) => { + for other_fields.iter().enumerate().advance |(i, pair)| { + enum_matching_fields[i].push(pair.second()); + } + } } } let field_tuples = do self_vec.iter() .zip(enum_matching_fields.iter()) - .transform |(&(id, self_f), &other)| { - (id, self_f, other) + .transform |(&(id, self_f), other)| { + (id, self_f, copy *other) }.collect(); substructure = EnumMatching(variant_index, variant, field_tuples); } @@ -892,8 +896,8 @@ pub fn create_subpatterns(cx: @ExtCtxt, field_paths: ~[ast::Path], mutbl: ast::mutability) -> ~[@ast::pat] { - do field_paths.map |&path| { - cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), path, None)) + do field_paths.map |path| { + cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), copy *path, None)) } } @@ -1015,7 +1019,8 @@ left-to-right (`true`) or right-to-left (`false`). pub fn cs_fold(use_foldl: bool, f: &fn(@ExtCtxt, span, old: @expr, - self_f: @expr, other_fs: &[@expr]) -> @expr, + self_f: @expr, + other_fs: &[@expr]) -> @expr, base: @expr, enum_nonmatch_f: EnumNonMatchFunc, cx: @ExtCtxt, span: span, @@ -1023,11 +1028,13 @@ pub fn cs_fold(use_foldl: bool, match *substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { if use_foldl { - do all_fields.iter().fold(base) |old, &(_, self_f, other_fs)| { + do all_fields.iter().fold(base) |old, triple| { + let (_, self_f, other_fs) = copy *triple; f(cx, span, old, self_f, other_fs) } } else { - do all_fields.rev_iter().fold(base) |old, &(_, self_f, other_fs)| { + do all_fields.rev_iter().fold(base) |old, triple| { + let (_, self_f, other_fs) = copy *triple; f(cx, span, old, self_f, other_fs) } } @@ -1059,7 +1066,8 @@ pub fn cs_same_method(f: &fn(@ExtCtxt, span, ~[@expr]) -> @expr, match *substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) - let called = do all_fields.map |&(_, self_field, other_fields)| { + let called = do all_fields.map |triple| { + let (_, self_field, other_fields) = copy *triple; cx.expr_method_call(span, self_field, substructure.method_ident, diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 98fc9aa61784d..478c086199011 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -137,7 +137,7 @@ impl gen_send for message { let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str()); let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(&n, t)| cx.arg(span, cx.ident_of(n), copy *t)).collect(); + .transform(|(n, t)| cx.arg(span, cx.ident_of(*n), copy *t)).collect(); let args_ast = vec::append( ~[cx.arg(span, diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 2fe8456c2749c..75424b60390d7 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -215,8 +215,8 @@ pub fn visit>( // the copy keywords prevent recursive use of dvec let states: ~[Tstate] = do (copy proto.states).iter().transform |&s| { - let messages: ~[Tmessage] = do (copy s.messages).iter().transform |&m| { - let message(name, span, tys, this, next) = m; + let messages: ~[Tmessage] = do (copy s.messages).iter().transform |m| { + let message(name, span, tys, this, next) = copy *m; visitor.visit_message(name, span, tys, this, next) }.collect(); visitor.visit_state(s, messages) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c43b350abdbf7..8666c84bbefe1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3914,7 +3914,7 @@ impl Parser { }; let full_path = full_path.normalize(); - let maybe_i = do self.sess.included_mod_stack.iter().position |&p| { p == full_path }; + let maybe_i = do self.sess.included_mod_stack.iter().position |p| { *p == full_path }; match maybe_i { Some(i) => { let stack = &self.sess.included_mod_stack; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b545c56778e90..c37108536154d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -147,7 +147,7 @@ pub fn ty_to_str(ty: &ast::Ty, intr: @ident_interner) -> ~str { } pub fn pat_to_str(pat: &ast::pat, intr: @ident_interner) -> ~str { - to_str(pat, print_irrefutable_pat, intr) + to_str(pat, print_pat, intr) } pub fn expr_to_str(e: &ast::expr, intr: @ident_interner) -> ~str { @@ -1240,7 +1240,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { if first { first = false; } else { space(s.s); word_space(s, "|"); } - print_refutable_pat(s, *p); + print_pat(s, *p); } space(s.s); match arm.guard { @@ -1434,7 +1434,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { } pub fn print_local_decl(s: @ps, loc: &ast::local) { - print_irrefutable_pat(s, loc.node.pat); + print_pat(s, loc.node.pat); match loc.node.ty.node { ast::ty_infer => (), _ => { word_space(s, ":"); print_type(s, &loc.node.ty); } @@ -1526,15 +1526,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path, print_path_(s, path, false, bounds) } -pub fn print_irrefutable_pat(s: @ps, pat: &ast::pat) { - print_pat(s, pat, false) -} - -pub fn print_refutable_pat(s: @ps, pat: &ast::pat) { - print_pat(s, pat, true) -} - -pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { +pub fn print_pat(s: @ps, pat: &ast::pat) { maybe_print_comment(s, pat.span.lo); let ann_node = node_pat(s, pat); (s.ann.pre)(ann_node); @@ -1543,20 +1535,18 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { match pat.node { ast::pat_wild => word(s.s, "_"), ast::pat_ident(binding_mode, ref path, sub) => { - if refutable { - match binding_mode { - ast::bind_by_ref(mutbl) => { - word_nbsp(s, "ref"); - print_mutability(s, mutbl); - } - ast::bind_infer => {} + match binding_mode { + ast::bind_by_ref(mutbl) => { + word_nbsp(s, "ref"); + print_mutability(s, mutbl); } + ast::bind_infer => {} } print_path(s, path, true); match sub { Some(p) => { word(s.s, "@"); - print_pat(s, p, refutable); + print_pat(s, p); } None => () } @@ -1569,7 +1559,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { if !args.is_empty() { popen(s); commasep(s, inconsistent, *args, - |s, &p| print_pat(s, p, refutable)); + |s, &p| print_pat(s, p)); pclose(s); } else { } } @@ -1578,16 +1568,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { ast::pat_struct(ref path, ref fields, etc) => { print_path(s, path, true); word(s.s, "{"); - fn print_field(s: @ps, f: &ast::field_pat, refutable: bool) { + fn print_field(s: @ps, f: &ast::field_pat) { cbox(s, indent_unit); print_ident(s, f.ident); word_space(s, ":"); - print_pat(s, f.pat, refutable); + print_pat(s, f.pat); end(s); } fn get_span(f: &ast::field_pat) -> codemap::span { return f.pat.span; } commasep_cmnt(s, consistent, *fields, - |s, f| print_field(s,f,refutable), + |s, f| print_field(s,f), get_span); if etc { if fields.len() != 0u { word_space(s, ","); } @@ -1597,7 +1587,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { } ast::pat_tup(ref elts) => { popen(s); - commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p, refutable)); + commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p)); if elts.len() == 1 { word(s.s, ","); } @@ -1605,15 +1595,15 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { } ast::pat_box(inner) => { word(s.s, "@"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_uniq(inner) => { word(s.s, "~"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_region(inner) => { word(s.s, "&"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_lit(e) => print_expr(s, e), ast::pat_range(begin, end) => { @@ -1625,16 +1615,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { ast::pat_vec(ref before, slice, ref after) => { word(s.s, "["); do commasep(s, inconsistent, *before) |s, &p| { - print_pat(s, p, refutable); + print_pat(s, p); } for slice.iter().advance |&p| { if !before.is_empty() { word_space(s, ","); } word(s.s, ".."); - print_pat(s, p, refutable); + print_pat(s, p); if !after.is_empty() { word_space(s, ","); } } do commasep(s, inconsistent, *after) |s, &p| { - print_pat(s, p, refutable); + print_pat(s, p); } word(s.s, "]"); } @@ -1888,7 +1878,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) { word_space(s, "mut"); } match input.ty.node { - ast::ty_infer => print_irrefutable_pat(s, input.pat), + ast::ty_infer => print_pat(s, input.pat), _ => { match input.pat.node { ast::pat_ident(_, ref path, _) if @@ -1897,7 +1887,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) { // Do nothing. } _ => { - print_irrefutable_pat(s, input.pat); + print_pat(s, input.pat); word(s.s, ":"); space(s.s); } diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index a49b52bffe153..012333b931ec7 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -39,10 +39,6 @@ rust_opaque_box *boxed_region::malloc(type_desc *td, size_t body_size) { rust_opaque_box *boxed_region::realloc(rust_opaque_box *box, size_t new_size) { - // We also get called on the unique-vec-in-managed-heap path. - assert(box->ref_count == 1 || - box->ref_count == (size_t)(-2)); - size_t total_size = new_size + sizeof(rust_opaque_box); rust_opaque_box *new_box = (rust_opaque_box*)backing_region->realloc(box, total_size); diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 974cdb0a0ef63..919c4daeb253b 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -56,8 +56,8 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { let mut pairs = ~[]; // map -> [(k,%)] - for mm.iter().advance |(&key, &val)| { - pairs.push((key, pct(val, total))); + for mm.iter().advance |(key, &val)| { + pairs.push((copy *key, pct(val, total))); } let pairs_sorted = sortKV(pairs); diff --git a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs new file mode 100644 index 0000000000000..c99a1ee60d7fd --- /dev/null +++ b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs @@ -0,0 +1,16 @@ +fn with(f: &fn(&~str)) {} + +fn arg_item(&_x: &~str) {} + //~^ ERROR cannot move out of dereference of & pointer + +fn arg_closure() { + with(|&_x| ()) + //~^ ERROR cannot move out of dereference of & pointer +} + +fn let_pat() { + let &_x = &~"hi"; + //~^ ERROR cannot move out of dereference of & pointer +} + +pub fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs new file mode 100644 index 0000000000000..4407329f49775 --- /dev/null +++ b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs @@ -0,0 +1,22 @@ +struct S {f:~str} +impl Drop for S { + fn drop(&self) { println(self.f); } +} + +fn move_in_match() { + match S {f:~"foo"} { + S {f:_s} => {} + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + } +} + +fn move_in_let() { + let S {f:_s} = S {f:~"foo"}; + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn move_in_fn_arg(S {f:_s}: S) { + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs new file mode 100644 index 0000000000000..400a4f07951fc --- /dev/null +++ b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -0,0 +1,22 @@ +struct S(~str); +impl Drop for S { + fn drop(&self) { println(**self); } +} + +fn move_in_match() { + match S(~"foo") { + S(_s) => {} + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + } +} + +fn move_in_let() { + let S(_s) = S(~"foo"); + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn move_in_fn_arg(S(_s): S) { + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs index dec976e0a6068..91a3d843cd4ac 100644 --- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs @@ -11,7 +11,7 @@ pub fn main() { Foo { string: ~"baz" } ]; match x { - [first, ..tail] => { + [_, ..tail] => { match tail { [Foo { string: a }, Foo { string: b }] => { //~^ ERROR cannot move out of dereference of & pointer diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 81f052918edd8..36ae5f8820892 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -17,4 +17,41 @@ fn b() { } } +fn c() { + let mut vec = [~1, ~2, ~3]; + match vec { + [_a, .._b] => { + //~^ ERROR cannot move out + + // Note: `_a` is *moved* here, but `b` is borrowing, + // hence illegal. + // + // See comment in middle/borrowck/gather_loans/mod.rs + // in the case covering these sorts of vectors. + } + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + +fn d() { + let mut vec = [~1, ~2, ~3]; + match vec { + [.._a, _b] => { + //~^ ERROR cannot move out + } + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + +fn e() { + let mut vec = [~1, ~2, ~3]; + match vec { + [_a, _b, _c] => {} + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + fn main() {} diff --git a/src/test/compile-fail/regions-ref-in-fn-arg.rs b/src/test/compile-fail/regions-ref-in-fn-arg.rs new file mode 100644 index 0000000000000..f90fe924587df --- /dev/null +++ b/src/test/compile-fail/regions-ref-in-fn-arg.rs @@ -0,0 +1,11 @@ +fn arg_item(~ref x: ~int) -> &'static int { + x //~^ ERROR borrowed value does not live long enough +} + +fn with(f: &fn(~int) -> R) -> R { f(~3) } + +fn arg_closure() -> &'static int { + with(|~ref x| x) //~ ERROR borrowed value does not live long enough +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 9a3ba32390c72..92344aae73e6d 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -68,7 +68,7 @@ fn main() { check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;"); let pat = quote_pat!(Some(_)); - check_pp(ext_cx, pat, pprust::print_refutable_pat, ~"Some(_)"); + check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)"); } diff --git a/src/test/run-pass/borrowck-newtype-issue-2573.rs b/src/test/run-pass/borrowck-newtype-issue-2573.rs deleted file mode 100644 index 5f0c7cad6191c..0000000000000 --- a/src/test/run-pass/borrowck-newtype-issue-2573.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct foo {bar: baz} - -struct baz_ {baz: int} - -type baz = @mut baz_; - -trait frob { - fn frob(&self); -} - -impl frob for foo { - fn frob(&self) { - really_impure(self.bar); - } -} - -// Override default mode so that we are passing by value -fn really_impure(bar: baz) { - bar.baz = 3; -} - -pub fn main() {} diff --git a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs index 056397f55ff26..5da7a6f2b56cc 100644 --- a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs +++ b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs @@ -28,12 +28,12 @@ fn main() { - let a = @mut [3i]; + let a = @mut 3i; let b = @mut [a]; - let c = @mut b; + let c = @mut [3]; // this should freeze `a` only - let _x: &mut [int] = c[0]; + let _x: &mut int = a; // hence these writes should not fail: b[0] = b[0]; diff --git a/src/test/run-pass/func-arg-incomplete-pattern.rs b/src/test/run-pass/func-arg-incomplete-pattern.rs new file mode 100644 index 0000000000000..b08d3beae1bfa --- /dev/null +++ b/src/test/run-pass/func-arg-incomplete-pattern.rs @@ -0,0 +1,20 @@ +// Test that we do not leak when the arg pattern must drop part of the +// argument (in this case, the `y` field). + +struct Foo { + x: ~uint, + y: ~uint, +} + +fn foo(Foo {x, _}: Foo) -> *uint { + let addr: *uint = &*x; + addr +} + +fn main() { + let obj = ~1; + let objptr: *uint = &*obj; + let f = Foo {x: obj, y: ~2}; + let xptr = foo(f); + assert_eq!(objptr, xptr); +} \ No newline at end of file diff --git a/src/test/run-pass/func-arg-ref-pattern.rs b/src/test/run-pass/func-arg-ref-pattern.rs new file mode 100644 index 0000000000000..84c2b3acf3580 --- /dev/null +++ b/src/test/run-pass/func-arg-ref-pattern.rs @@ -0,0 +1,24 @@ +// exec-env:RUST_POISON_ON_FREE=1 + +// Test argument patterns where we create refs to the inside of `~` +// boxes. Make sure that we don't free the box as we match the +// pattern. + +fn getaddr(~ref x: ~uint) -> *uint { + let addr: *uint = &*x; + addr +} + +fn checkval(~ref x: ~uint) -> uint { + *x +} + +fn main() { + let obj = ~1; + let objptr: *uint = &*obj; + let xptr = getaddr(obj); + assert_eq!(objptr, xptr); + + let obj = ~22; + assert_eq!(checkval(obj), 22); +} diff --git a/src/test/run-pass/func-arg-wild-pattern.rs b/src/test/run-pass/func-arg-wild-pattern.rs new file mode 100644 index 0000000000000..c2d60c8532993 --- /dev/null +++ b/src/test/run-pass/func-arg-wild-pattern.rs @@ -0,0 +1,10 @@ +// Test that we can compile code that uses a `_` in function argument +// patterns. + +fn foo((x, _): (int, int)) -> int { + x +} + +fn main() { + assert_eq!(foo((22, 23)), 22); +} diff --git a/src/test/run-pass/let-destruct-ref.rs b/src/test/run-pass/let-destruct-ref.rs new file mode 100644 index 0000000000000..7f3f9110b1c5c --- /dev/null +++ b/src/test/run-pass/let-destruct-ref.rs @@ -0,0 +1,5 @@ +fn main() { + let x = ~"hello"; + let ref y = x; + assert_eq!(x.slice(0, x.len()), y.slice(0, y.len())); +} diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs new file mode 100644 index 0000000000000..2a629b62534ec --- /dev/null +++ b/src/test/run-pass/match-drop-strs-issue-4541.rs @@ -0,0 +1,27 @@ +// Tests a tricky scenario involving string matching, +// copying, and moving to ensure that we don't segfault +// or double-free, as we were wont to do in the past. + +use std::io; +use std::os; + +fn parse_args() -> ~str { + let args = os::args(); + let mut n = 0; + + while n < args.len() { + match copy args[n] { + ~"-v" => (), + s => { + return s; + } + } + n += 1; + } + + return ~"" +} + +fn main() { + io::println(parse_args()); +} diff --git a/src/test/run-pass/match-pattern-drop.rs b/src/test/run-pass/match-pattern-drop.rs index 71bbb1768e892..3ce4ef8a94cd5 100644 --- a/src/test/run-pass/match-pattern-drop.rs +++ b/src/test/run-pass/match-pattern-drop.rs @@ -14,8 +14,11 @@ enum t { make_t(@int), clam, } fn foo(s: @int) { + debug!(::std::sys::refcount(s)); let count = ::std::sys::refcount(s); let x: t = make_t(s); // ref up + assert_eq!(::std::sys::refcount(s), count + 1u); + debug!(::std::sys::refcount(s)); match x { make_t(y) => { @@ -38,6 +41,5 @@ pub fn main() { debug!("%u", ::std::sys::refcount(s)); let count2 = ::std::sys::refcount(s); - let _ = ::std::sys::refcount(s); // don't get bitten by last-use. assert_eq!(count, count2); } diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 4ce229526ffba..f8c369c2e5f7e 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -163,8 +163,8 @@ pub fn main() { visit_ty::(vv); visit_ty::<~[int]>(vv); - for v.types.iter().advance |&s| { - println(fmt!("type: %s", s)); + for v.types.iter().advance |s| { + println(fmt!("type: %s", copy *s)); } assert_eq!((*v.types).clone(), ~[~"bool", ~"int", ~"i8", ~"i16", ~"[", ~"int", ~"]"]); } diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 6e1a47ad2dfd3..27f4fc833511a 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -9,7 +9,7 @@ pub fn main() { Foo { string: ~"baz" } ]; match x { - [first, ..tail] => { + [ref first, ..tail] => { assert!(first.string == ~"foo"); assert_eq!(tail.len(), 2); assert!(tail[0].string == ~"bar");