about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBrian Koropoff <bkoropoff@gmail.com>2014-10-02 19:43:16 -0700
committerBrian Koropoff <bkoropoff@gmail.com>2014-10-02 21:08:45 -0700
commitc4c19fe96003bb5bdaa6ca35603eb4220b1d5ca8 (patch)
treee96a196a98ac5c4abce1955e5495aa459b49614f /src
parent72dc0f5f82efcf891581fdc3ec15eb46f38cd718 (diff)
downloadrust-c4c19fe96003bb5bdaa6ca35603eb4220b1d5ca8.tar.gz
rust-c4c19fe96003bb5bdaa6ca35603eb4220b1d5ca8.zip
Correctly trans capture-by-ref unboxed closures
Store references to the freevars instead of copies when constructing
the environment and insert an additional load when reading them from
the environment.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/closure.rs19
1 files changed, 16 insertions, 3 deletions
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index f08736335c3..1e2e8c589c6 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -301,6 +301,7 @@ fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 fn load_unboxed_closure_environment<'blk, 'tcx>(
                                     bcx: Block<'blk, 'tcx>,
                                     arg_scope_id: ScopeId,
+                                    freevar_mode: ast::CaptureClause,
                                     freevars: &Vec<ty::Freevar>,
                                     closure_id: ast::DefId)
                                     -> Block<'blk, 'tcx> {
@@ -326,11 +327,14 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
     };
 
     for (i, freevar) in freevars.iter().enumerate() {
-        let upvar_ptr = GEPi(bcx, llenv, [0, i]);
+        let mut upvar_ptr = GEPi(bcx, llenv, [0, i]);
+        if freevar_mode == ast::CaptureByRef {
+            upvar_ptr = Load(bcx, upvar_ptr);
+        }
         let def_id = freevar.def.def_id();
         bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
 
-        if kind == ty::FnOnceUnboxedClosureKind {
+        if kind == ty::FnOnceUnboxedClosureKind && freevar_mode == ast::CaptureByValue {
             bcx.fcx.schedule_drop_mem(arg_scope_id,
                                       upvar_ptr,
                                       node_id_type(bcx, def_id.node))
@@ -477,6 +481,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
     let freevars: Vec<ty::Freevar> =
         ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect());
     let freevars_ptr = &freevars;
+    let freevar_mode = bcx.tcx().capture_mode(id);
 
     trans_closure(bcx.ccx(),
                   decl,
@@ -493,6 +498,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
                   |bcx, arg_scope| {
                       load_unboxed_closure_environment(bcx,
                                                        arg_scope,
+                                                       freevar_mode,
                                                        freevars_ptr,
                                                        closure_id)
                   });
@@ -518,7 +524,14 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
                                                    dest_addr,
                                                    0,
                                                    i);
-        bcx = datum.store_to(bcx, upvar_slot_dest);
+        match freevar_mode {
+            ast::CaptureByValue => {
+                bcx = datum.store_to(bcx, upvar_slot_dest);
+            }
+            ast::CaptureByRef => {
+                Store(bcx, datum.to_llref(), upvar_slot_dest);
+            }
+        }
     }
     adt::trans_set_discr(bcx, &*repr, dest_addr, 0);