about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-01-10 06:29:26 -0800
committerNiko Matsakis <niko@alum.mit.edu>2013-01-10 13:17:25 -0800
commit737e115646ec79dac05d61232d89e59d8da751a9 (patch)
tree174f3520372763ff341d9ea9a55a61874250fd04 /src
parenteaa256509ede9d1277e7b498fdea4548e1851647 (diff)
downloadrust-737e115646ec79dac05d61232d89e59d8da751a9.tar.gz
rust-737e115646ec79dac05d61232d89e59d8da751a9.zip
mode: reset mode on entry to fn body.
This is an interim fix to address the "Beware!" unsoundness.  I have a
more comprehensive rewrite of mode.rs in the pipeline.

r=pcwalton
Diffstat (limited to 'src')
-rw-r--r--src/libcore/condition.rs2
-rw-r--r--src/librustc/driver/driver.rs4
-rw-r--r--src/librustc/metadata/creader.rs3
-rw-r--r--src/librustc/middle/check_match.rs5
-rw-r--r--src/librustc/middle/mode.rs23
-rw-r--r--src/librustc/middle/trans/callee.rs3
-rw-r--r--src/librustc/middle/trans/closure.rs2
-rw-r--r--src/librustc/middle/trans/common.rs2
-rw-r--r--src/librustc/middle/trans/inline.rs3
-rw-r--r--src/librustc/middle/trans/meth.rs3
-rw-r--r--src/librustc/middle/trans/monomorphize.rs4
-rw-r--r--src/librustc/middle/ty.rs4
-rw-r--r--src/librustc/middle/typeck/check/mod.rs32
-rw-r--r--src/test/compile-fail/access-mode-in-closures.rs10
-rw-r--r--src/test/run-fail/unwind-lambda.rs2
-rw-r--r--src/test/run-pass/last-use-corner-cases.rs4
-rw-r--r--src/test/run-pass/monad.rs4
17 files changed, 69 insertions, 41 deletions
diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs
index a40121445fa..c4001717ca1 100644
--- a/src/libcore/condition.rs
+++ b/src/libcore/condition.rs
@@ -37,7 +37,7 @@ impl<T, U> Condition<T, U> {
 
     fn raise(t: T) -> U {
         let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
-        self.raise_default(t, || fail msg)
+        self.raise_default(t, || fail copy msg)
     }
 
     fn raise_default(t: T, default: &fn() -> U) -> U {
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index b4a9a83992d..b4366428a90 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -188,7 +188,7 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg,
     -> {crate: @ast::crate, tcx: Option<ty::ctxt>} {
     let time_passes = sess.time_passes();
     let mut crate = time(time_passes, ~"parsing",
-                         ||parse_input(sess, cfg, input) );
+                         || parse_input(sess, copy cfg, input) );
     if upto == cu_parse { return {crate: crate, tcx: None}; }
 
     sess.building_library = session::building_library(
@@ -201,7 +201,7 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg,
         front::test::modify_for_testing(sess, crate));
 
     crate = time(time_passes, ~"expansion", ||
-        syntax::ext::expand::expand_crate(sess.parse_sess, cfg,
+        syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg,
                                           crate));
 
     if upto == cu_expand { return {crate: crate, tcx: None}; }
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index a731aa8db97..608f2b5c233 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -86,7 +86,8 @@ fn warn_if_multiple_versions(e: env, diag: span_handler,
             /*bad*/copy *crate_cache.last().metas);
         let (matches, non_matches) =
             partition(crate_cache.map_to_vec(|&entry| {
-                let othername = loader::crate_name_from_metas(*entry.metas);
+                let othername = loader::crate_name_from_metas(
+                    copy *entry.metas);
                 if name == othername {
                     Left(entry)
                 } else {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index c99b5757baa..0a063d115e1 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -275,7 +275,7 @@ fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: ~[@pat]) -> useful {
             }
           }
           Some(ref ctor) => {
-            match is_useful(cx, vec::filter_map(m, |r| default(cx, *r)),
+            match is_useful(cx, vec::filter_map(m, |r| default(cx, copy *r)),
                             vec::tail(v)) {
               useful_ => useful(left_ty, (/*bad*/copy *ctor)),
               ref u => (/*bad*/copy *u)
@@ -292,7 +292,8 @@ fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: ~[@pat]) -> useful {
 
 fn is_useful_specialized(cx: @MatchCheckCtxt, m: matrix, +v: ~[@pat],
                          +ctor: ctor, arity: uint, lty: ty::t) -> useful {
-    let ms = vec::filter_map(m, |r| specialize(cx, *r, ctor, arity, lty));
+    let ms = vec::filter_map(m, |r| specialize(cx, copy *r,
+                                               ctor, arity, lty));
     let could_be_useful = is_useful(
         cx, ms, specialize(cx, v, ctor, arity, lty).get());
     match could_be_useful {
diff --git a/src/librustc/middle/mode.rs b/src/librustc/middle/mode.rs
index 1e24ff9f5e4..7c2b518dbe9 100644
--- a/src/librustc/middle/mode.rs
+++ b/src/librustc/middle/mode.rs
@@ -23,8 +23,11 @@ use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
 use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
 use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
 use syntax::ast::{sty_uniq, sty_value, uniq};
+use syntax::ast::{fn_decl, blk};
 use syntax::visit;
-use syntax::visit::vt;
+use syntax::visit::{fn_kind, vt};
+use syntax::print::pprust;
+use syntax::codemap::span;
 
 struct VisitContext {
     tcx: ctxt,
@@ -32,6 +35,17 @@ struct VisitContext {
     mode: ValueMode,
 }
 
+fn compute_modes_for_fn(fk: fn_kind,
+                        decl: fn_decl,
+                        body: blk,
+                        sp: span,
+                        id: node_id,
+                        &&cx: VisitContext,
+                        v: vt<VisitContext>) {
+    let body_cx = VisitContext { mode: MoveValue, ..cx };
+    visit::visit_fn(fk, decl, body, sp, id, body_cx, v);
+}
+
 fn compute_modes_for_fn_args(callee_id: node_id,
                              args: &[@expr],
                              last_arg_is_block: bool,
@@ -79,6 +93,10 @@ fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
 fn compute_modes_for_expr(expr: @expr,
                           &&cx: VisitContext,
                           v: vt<VisitContext>) {
+    debug!("compute_modes_for_expr(expr=%?/%s, mode=%?)",
+           expr.id, pprust::expr_to_str(expr, cx.tcx.sess.intr()),
+           cx.mode);
+
     // Adjust the mode if there was an implicit reference here.
     let cx = match cx.tcx.adjustments.find(expr.id) {
         None => cx,
@@ -91,7 +109,7 @@ fn compute_modes_for_expr(expr: @expr,
         }
     };
 
-    match /*bad*/copy expr.node {
+    match copy expr.node {
         expr_call(callee, args, is_block) => {
             let callee_cx = VisitContext { mode: ReadValue, ..cx };
             compute_modes_for_expr(callee, callee_cx, v);
@@ -235,6 +253,7 @@ fn compute_modes_for_pat(pat: @pat,
 
 pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
     let visitor = visit::mk_vt(@visit::Visitor {
+        visit_fn: compute_modes_for_fn,
         visit_expr: compute_modes_for_expr,
         visit_pat: compute_modes_for_pat,
         .. *visit::default_visitor()
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index d90673b31bc..9b9d3467934 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -366,7 +366,8 @@ fn trans_rtcall_or_lang_call_with_type_params(bcx: block,
         bcx, None, fty, rty,
         |bcx| {
             let callee =
-                trans_fn_ref_with_vtables_to_callee(bcx, did, 0, type_params,
+                trans_fn_ref_with_vtables_to_callee(bcx, did, 0,
+                                                    copy type_params,
                                                     None);
 
             let new_llval;
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index 63287055685..846c5d8edb2 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -413,7 +413,7 @@ fn trans_expr_fn(bcx: block,
                                                    ret_handle);
         trans_closure(ccx, /*bad*/copy sub_path, decl, body, llfn, no_self,
                       /*bad*/copy bcx.fcx.param_substs, id, None, |fcx| {
-            load_environment(fcx, cdata_ty, cap_vars,
+            load_environment(fcx, cdata_ty, copy cap_vars,
                              ret_handle.is_some(), proto);
                       }, |bcx| {
             if is_loop_body.is_some() {
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 3bec973fc90..85f4389b0c4 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -1309,7 +1309,7 @@ fn node_vtables(bcx: block, id: ast::node_id) -> Option<typeck::vtable_res> {
 fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
     -> typeck::vtable_res
 {
-    @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, *d))
+    @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d))
 }
 
 // Apply the typaram substitutions in the fn_ctxt to a vtable. This should
diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs
index 447b4455adf..98842f8b073 100644
--- a/src/librustc/middle/trans/inline.rs
+++ b/src/librustc/middle/trans/inline.rs
@@ -43,7 +43,8 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id,
         match csearch::maybe_get_item_ast(
             ccx.tcx, fn_id,
             |a,b,c,d| {
-                astencode::decode_inlined_item(a, b, ccx.maps, c, d)
+                astencode::decode_inlined_item(a, b, ccx.maps,
+                                               /*bad*/ copy c, d)
             }) {
 
           csearch::not_found => {
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index 9631fd8b389..53ed1cf02ff 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -780,7 +780,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
 
     let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
     make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| {
-        let fty = ty::subst_tps(tcx, substs, None, ty::mk_fn(tcx, im.fty));
+        let fty = ty::subst_tps(tcx, substs, None,
+                                ty::mk_fn(tcx, copy im.fty));
         if (*im.tps).len() > 0u || ty::type_has_self(fty) {
             debug!("(making impl vtable) method has self or type params: %s",
                    tcx.sess.str_of(im.ident));
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 60ad1b83807..6ead78a28dd 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -335,7 +335,7 @@ fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
       Some(ref uses) => {
         vec::map2(precise_param_ids, *uses, |id, uses| {
             if ccx.sess.no_monomorphic_collapse() {
-                match *id {
+                match copy *id {
                     (a, b) => mono_precise(a, b)
                 }
             } else {
@@ -379,7 +379,7 @@ fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
       }
       None => {
           precise_param_ids.map(|x| {
-              let (a, b) = *x;
+              let (a, b) = copy *x;
               mono_precise(a, b)
           })
       }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index b4cbc6c3f0e..04085a2c047 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3905,10 +3905,10 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
             let mut disr_val = -1;
             @vec::map(variants, |variant| {
                 match variant.node.kind {
-                    ast::tuple_variant_kind(args) => {
+                    ast::tuple_variant_kind(ref args) => {
                         let ctor_ty = node_id_to_type(cx, variant.node.id);
                         let arg_tys = {
-                            if vec::len(args) > 0u {
+                            if args.len() > 0u {
                                 ty_fn_args(ctor_ty).map(|a| a.ty)
                             } else {
                                 ~[]
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index ff99ee8590a..ae39c674030 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1507,12 +1507,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
     // resolution is not possible (e.g., no constraints yet present), just
     // returns `none`.
     fn unpack_expected<O: Copy>(fcx: @fn_ctxt, expected: Option<ty::t>,
-                                unpack: fn(ty::sty) -> Option<O>)
+                                unpack: fn(&ty::sty) -> Option<O>)
         -> Option<O> {
         match expected {
             Some(t) => {
                 match resolve_type(fcx.infcx(), t, force_tvar) {
-                    Ok(t) => unpack(ty::get(t).sty),
+                    Ok(t) => unpack(&ty::get(t).sty),
                     _ => None
                 }
             }
@@ -1537,7 +1537,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         // to impure and block. Note that we only will use those for
         // block syntax lambdas; that is, lambdas without explicit
         // protos.
-        let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
+        let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
         let (expected_tys,
              expected_purity,
              expected_proto,
@@ -1969,8 +1969,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
       ast::expr_unary(unop, oprnd) => {
         let exp_inner = do unpack_expected(fcx, expected) |sty| {
             match unop {
-              ast::box(_) | ast::uniq(_) => match sty {
-                ty::ty_box(mt) | ty::ty_uniq(mt) => Some(mt.ty),
+              ast::box(_) | ast::uniq(_) => match *sty {
+                ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty),
                 _ => None
               },
               ast::not | ast::neg => expected,
@@ -2050,8 +2050,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         fcx.write_ty(id, oprnd_t);
       }
       ast::expr_addr_of(mutbl, oprnd) => {
-        bot = check_expr(fcx, oprnd, unpack_expected(fcx, expected, |ty|
-            match ty { ty::ty_rptr(_, mt) => Some(mt.ty), _ => None }
+        bot = check_expr(fcx, oprnd, unpack_expected(fcx, expected, |sty|
+            match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty), _ => None }
         ));
 
         // Note: at this point, we cannot say what the best lifetime
@@ -2177,7 +2177,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         // 1. a closure that returns a bool is expected
         // 2. the closure that was given returns unit
         let mut err_happened = false;
-        let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
+        let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
         let inner_ty = match expected_sty {
           Some(ty::ty_fn(ref fty)) => {
             match fcx.mk_subty(false, expr.span,
@@ -2240,7 +2240,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
       }
       ast::expr_do_body(b) => {
-        let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
+        let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
         let inner_ty = match expected_sty {
           Some(ty::ty_fn(ref fty)) => {
               ty::mk_fn(tcx, (/*bad*/copy *fty))
@@ -2349,11 +2349,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
       }
       ast::expr_tup(elts) => {
         let flds = unpack_expected(fcx, expected, |sty| {
-            // XXX: Beware! If you remove `copy` below, the borrow checker
-            // will NOT complain, but you will get a segfault at runtime! This
-            // is because the mode computation is currently unaware of
-            // argument modes.
-            match copy sty { ty::ty_tup(flds) => Some(flds), _ => None }
+            match *sty { ty::ty_tup(ref flds) => Some(copy *flds), _ => None }
         });
         let elt_ts = do elts.mapi |i, e| {
             check_expr(fcx, *e, flds.map(|fs| fs[i]));
@@ -2368,12 +2364,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
             Some(fcx.expr_ty(base.get()))
         } else { expected };
         let flds = unpack_expected(fcx, expected, |sty|
-            // XXX: Beware! If you remove `copy` below, the borrow checker
-            // will NOT complain, but you will get a segfault at runtime! This
-            // is because the mode computation is currently unaware of
-            // argument modes.
-            match copy sty {
-                ty::ty_rec(flds) => Some(flds),
+            match *sty {
+                ty::ty_rec(ref flds) => Some(copy *flds),
                 _ => None
             }
         );
diff --git a/src/test/compile-fail/access-mode-in-closures.rs b/src/test/compile-fail/access-mode-in-closures.rs
new file mode 100644
index 00000000000..32ac756aaff
--- /dev/null
+++ b/src/test/compile-fail/access-mode-in-closures.rs
@@ -0,0 +1,10 @@
+enum sty = ~[int];
+
+fn unpack(unpack: &fn(v: &sty) -> ~[int]) {}
+
+fn main() {
+    let foo = unpack(|s| {
+        // Test that `s` is moved here.
+        match *s { sty(v) => v } //~ ERROR moving out of dereference of immutable & pointer
+    });
+}
diff --git a/src/test/run-fail/unwind-lambda.rs b/src/test/run-fail/unwind-lambda.rs
index 08457f07143..aee6f4e480c 100644
--- a/src/test/run-fail/unwind-lambda.rs
+++ b/src/test/run-fail/unwind-lambda.rs
@@ -15,7 +15,7 @@ fn main() {
     let carrots = @~"crunchy";
 
     fn@(tasties: @~str, macerate: fn(~str)) {
-        macerate(*tasties);
+        macerate(copy *tasties);
     } (carrots, |food| {
         let mush = food + cheese;
         let f = fn@() {
diff --git a/src/test/run-pass/last-use-corner-cases.rs b/src/test/run-pass/last-use-corner-cases.rs
index b4077863852..1dfccac8bce 100644
--- a/src/test/run-pass/last-use-corner-cases.rs
+++ b/src/test/run-pass/last-use-corner-cases.rs
@@ -39,6 +39,6 @@ fn main() {
     // Verify that blocks can't interfere with each other.
     fn two_blocks(a: fn(), b: fn()) { a(); b(); a(); b(); }
     let q = ~50;
-    two_blocks(|| { let a = q; assert *a == 50;},
-               || { let a = q; assert *a == 50;});
+    two_blocks(|| { let a = copy q; assert *a == 50;},
+               || { let a = copy q; assert *a == 50;});
 }
diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs
index 8abc8236b65..210defa5789 100644
--- a/src/test/run-pass/monad.rs
+++ b/src/test/run-pass/monad.rs
@@ -43,6 +43,8 @@ fn transform(x: Option<int>) -> Option<~str> {
 fn main() {
     assert transform(Some(10)) == Some(~"11");
     assert transform(None) == None;
-    assert (~[~"hi"]).bind(|x| ~[x, x + ~"!"] ).bind(|x| ~[x, x + ~"?"] ) ==
+    assert (~[~"hi"])
+        .bind(|x| ~[copy x, x + ~"!"] )
+        .bind(|x| ~[copy x, x + ~"?"] ) ==
         ~[~"hi", ~"hi?", ~"hi!", ~"hi!?"];
 }