diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs index 1a46d630d4f..c7a31b39ad5 100644 --- a/src/libcore/dvec.rs +++ b/src/libcore/dvec.rs @@ -131,12 +131,15 @@ impl extensions for dvec { impl extensions for dvec { #[doc = "Append a single item to the end of the list"] fn push(t: A) { - self.swap { |v| v += [t]; v } // more efficient than v + [t] + self.swap { |v| + let mut v <- v; v += [t]; v // more efficient than v + [t] + } } #[doc = "Remove and return the last element"] fn pop() -> A { self.borrow { |v| + let mut v <- v; let result = vec::pop(v); self.return(v); result @@ -157,6 +160,7 @@ impl extensions for dvec { "] fn push_slice(ts: [const A]/&, from_idx: uint, to_idx: uint) { self.swap { |v| + let mut v <- v; let new_len = vec::len(v) + to_idx - from_idx; vec::reserve(v, new_len); let mut i = from_idx; @@ -232,6 +236,10 @@ impl extensions for dvec { #[doc = "Overwrites the contents of the element at `idx` with `a`"] fn grow_set_elt(idx: uint, initval: A, val: A) { - self.swap { |v| vec::grow_set(v, idx, initval, val); v } + self.swap { |v| + let mut v <- v; + vec::grow_set(v, idx, initval, val); + v + } } } \ No newline at end of file diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index d6e7ce1b990..71a1e9d2d21 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -843,11 +843,8 @@ impl methods for check_loan_ctxt { self.bccx.cmt_to_repr(cmt)]; alt cmt.cat { - // Rvalues and locals can be moved: - cat_rvalue | cat_local(_) { } - - // Owned arguments can be moved: - cat_arg(_) if cmt.mutbl == m_mutbl { } + // Rvalues, locals, and arguments can be moved: + cat_rvalue | cat_local(_) | cat_arg(_) { } // We allow moving out of static items because the old code // did. This seems consistent with permitting moves out of @@ -1348,7 +1345,7 @@ impl categorize_methods for borrowck_ctxt { lp: none} } ast::by_move | ast::by_copy { - {m: m_mutbl, + {m: m_imm, lp: some(@lp_arg(vid))} } ast::by_ref { @@ -1506,7 +1503,7 @@ impl categorize_methods for borrowck_ctxt { cat_special(sk_heap_upvar) { "upvar" } cat_rvalue { "non-lvalue" } cat_local(_) { mut_str + " local variable" } - cat_arg(_) { mut_str + " argument" } + cat_arg(_) { "argument" } cat_deref(_, _, pk) { #fmt["dereference of %s %s pointer", mut_str, self.pk_to_sigil(pk)] } cat_stack_upvar(_) { mut_str + " upvar" } diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index 9b732d08052..3f82e647ab6 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -1506,10 +1506,7 @@ impl check_methods for @liveness { (*self.ir).add_spill(var); } some(lnk) { - self.report_illegal_read(span, lnk, var, moved_variable); - self.tcx.sess.span_note( - span, - "move of variable occurred here"); + self.report_illegal_move(span, lnk, var); } } } @@ -1637,6 +1634,44 @@ impl check_methods for @liveness { } } + fn report_illegal_move(move_span: span, + lnk: live_node_kind, + var: variable) { + + // the only time that it is possible to have a moved variable + // used by lnk_exit would be arguments or fields in a ctor. + // we give a slightly different error message in those cases. + if lnk == lnk_exit { + let vk = self.ir.var_kinds[*var]; + alt vk { + vk_arg(_, name, _) { + self.tcx.sess.span_err( + move_span, + #fmt["illegal move from argument `%s`, which is not \ + copy or move mode", name]); + ret; + } + vk_field(name) { + self.tcx.sess.span_err( + move_span, + #fmt["illegal move from field `%s`", name]); + ret; + } + vk_local(*) | vk_self | vk_implicit_ret { + self.tcx.sess.span_bug( + move_span, + #fmt["illegal reader (%?) for `%?`", + lnk, vk]); + } + } + } + + self.report_illegal_read(move_span, lnk, var, moved_variable); + self.tcx.sess.span_note( + move_span, "move of variable occurred here"); + + } + fn report_illegal_read(chk_span: span, lnk: live_node_kind, var: variable, @@ -1658,7 +1693,8 @@ impl check_methods for @liveness { span, #fmt["use of %s: `%s`", msg, name]); } - lnk_exit | lnk_vdef(_) { + lnk_exit | + lnk_vdef(_) { self.tcx.sess.span_bug( chk_span, #fmt["illegal reader: %?", lnk]); diff --git a/src/test/compile-fail/liveness-move-from-args.rs b/src/test/compile-fail/liveness-move-from-args.rs new file mode 100644 index 00000000000..0c3e594040b --- /dev/null +++ b/src/test/compile-fail/liveness-move-from-args.rs @@ -0,0 +1,24 @@ +fn take(-_x: int) { } + +fn from_by_value_arg(++x: int) { + take(x); //! ERROR illegal move from argument `x`, which is not copy or move mode +} + +fn from_by_mut_ref_arg(&x: int) { + take(x); //! ERROR illegal move from argument `x`, which is not copy or move mode +} + +fn from_by_ref_arg(&&x: int) { + take(x); //! ERROR illegal move from argument `x`, which is not copy or move mode +} + +fn from_copy_arg(+x: int) { + take(x); +} + +fn from_move_arg(-x: int) { + take(x); +} + +fn main() { +} diff --git a/src/test/compile-fail/mutable-arguments.rs b/src/test/compile-fail/mutable-arguments.rs new file mode 100644 index 00000000000..79e7f412163 --- /dev/null +++ b/src/test/compile-fail/mutable-arguments.rs @@ -0,0 +1,30 @@ +// Note: it would be nice to give fewer warnings in these cases. + +fn mutate_by_mut_ref(&x: uint) { + x = 0u; +} + +fn mutate_by_ref(&&x: uint) { + //!^ WARNING unused variable: `x` + x = 0u; //! ERROR assigning to argument +} + +fn mutate_by_val(++x: uint) { + //!^ WARNING unused variable: `x` + x = 0u; //! ERROR assigning to argument +} + +fn mutate_by_copy(+x: uint) { + //!^ WARNING unused variable: `x` + x = 0u; //! ERROR assigning to argument + //!^ WARNING value assigned to `x` is never read +} + +fn mutate_by_move(-x: uint) { + //!^ WARNING unused variable: `x` + x = 0u; //! ERROR assigning to argument + //!^ WARNING value assigned to `x` is never read +} + +fn main() { +} diff --git a/src/test/run-pass/argument-passing.rs b/src/test/run-pass/argument-passing.rs index 2f17efd3279..bd8f56eec0b 100644 --- a/src/test/run-pass/argument-passing.rs +++ b/src/test/run-pass/argument-passing.rs @@ -2,7 +2,6 @@ fn f1(a: {mut x: int}, &b: int, -c: int) -> int { let r = a.x + b + c; a.x = 0; b = 10; - c = 20; ret r; }