about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-12-05 22:57:58 -0800
committerPatrick Walton <pcwalton@mimiga.net>2012-12-05 22:57:58 -0800
commit7203be1109d6e29dce14a842d454922c665ade3f (patch)
tree393c19329ba186d774e2803dba5fd85faa754dae
parentb58e1f6690c16ee77e21cfab145a0ee307a00695 (diff)
downloadrust-7203be1109d6e29dce14a842d454922c665ade3f.tar.gz
rust-7203be1109d6e29dce14a842d454922c665ade3f.zip
librustc: Fix handling of `~` and `@` unary operators in mode computation. Closes #4114. rs=bugfix
-rw-r--r--src/librustc/metadata/tydecode.rs2
-rw-r--r--src/librustc/middle/mode.rs29
-rw-r--r--src/librustc/middle/typeck/check/mod.rs2
-rw-r--r--src/test/compile-fail/move-based-on-type-tuple.rs4
4 files changed, 24 insertions, 13 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index ab84ae6e061..9cad123edc5 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -316,7 +316,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
         match st.tcx.rcache.find({cnum: st.crate, pos: pos, len: len}) {
           Some(tt) => return tt,
           None => {
-            let ps = @{pos: pos ,.. *st};
+            let ps = @{pos: pos ,.. copy *st};
             let tt = parse_ty(ps, conv);
             st.tcx.rcache.insert({cnum: st.crate, pos: pos, len: len}, tt);
             return tt;
diff --git a/src/librustc/middle/mode.rs b/src/librustc/middle/mode.rs
index c763c9f7489..e1bea7714b3 100644
--- a/src/librustc/middle/mode.rs
+++ b/src/librustc/middle/mode.rs
@@ -4,12 +4,11 @@ use middle::typeck::{method_map, method_map_entry};
 
 use core::vec;
 use std::map::HashMap;
-use syntax::ast::{by_copy, by_move, by_ref, by_val, crate, expr, expr_assign};
-use syntax::ast::{expr_addr_of, expr_assign_op, expr_binary, expr_call};
-use syntax::ast::{expr_copy, expr_field, expr_index, expr_method_call};
-use syntax::ast::{expr_path, expr_swap, expr_unary, node_id, sty_uniq};
-use syntax::ast::{sty_value};
-use syntax::ast::{box, uniq, deref, not, neg, expr_match, expr_paren};
+use syntax::ast::{box, by_copy, by_move, by_ref, by_val, crate, deref, expr};
+use syntax::ast::{expr_addr_of, expr_assign, expr_assign_op, expr_binary};
+use syntax::ast::{expr_call, expr_copy, expr_field, expr_index, expr_match};
+use syntax::ast::{expr_method_call, expr_paren, expr_path, expr_swap};
+use syntax::ast::{expr_unary, neg, node_id, not, sty_uniq, sty_value, uniq};
 use syntax::visit;
 use syntax::visit::vt;
 
@@ -115,17 +114,25 @@ fn compute_modes_for_expr(expr: @expr,
             compute_modes_for_expr(arg, arg_cx, v);
         }
         expr_unary(unop, arg) => {
-            // Ditto.
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(arg, arg_cx, v);
-
             match unop {
                 deref => {
+                    // Derefs function as reads.
+                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
+                    compute_modes_for_expr(arg, arg_cx, v);
+
                     // This is an lvalue, so it needs a value mode recorded
                     // for it.
                     record_mode_for_expr(expr, cx);
                 }
-                box(_) | uniq(_) | not | neg => {}
+                box(_) | uniq(_) => {
+                    let arg_cx = VisitContext { mode: MoveValue, ..cx };
+                    compute_modes_for_expr(arg, arg_cx, v);
+                }
+                not | neg => {
+                    // Takes its argument by ref.
+                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
+                    compute_modes_for_expr(arg, arg_cx, v);
+                }
             }
         }
         expr_field(arg, _, _) => {
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 3b9ad6e7184..ecd29a6f643 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2457,7 +2457,7 @@ fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool {
 
 fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
     let fcx = match blk.node.rules {
-      ast::unsafe_blk => @fn_ctxt {purity: ast::unsafe_fn,.. *fcx0},
+      ast::unsafe_blk => @fn_ctxt {purity: ast::unsafe_fn,.. copy *fcx0},
       ast::default_blk => fcx0
     };
     do fcx.with_region_lb(blk.node.id) {
diff --git a/src/test/compile-fail/move-based-on-type-tuple.rs b/src/test/compile-fail/move-based-on-type-tuple.rs
new file mode 100644
index 00000000000..778bb8d557b
--- /dev/null
+++ b/src/test/compile-fail/move-based-on-type-tuple.rs
@@ -0,0 +1,4 @@
+fn dup(x: ~int) -> ~(~int,~int) { ~(x, x) } //~ ERROR use of moved variable
+fn main() {
+    dup(~3);
+}