about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/trans/base.rs65
-rw-r--r--src/librustc/middle/trans/callee.rs15
-rw-r--r--src/librustc/middle/trans/closure.rs8
-rw-r--r--src/librustc/middle/trans/common.rs14
-rw-r--r--src/librustc/middle/trans/controlflow.rs16
-rw-r--r--src/librustc/middle/trans/reflect.rs4
6 files changed, 81 insertions, 41 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 242a820c997..9c304f839db 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1210,16 +1210,23 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
     p
 }
 
-// Creates and returns space for, or returns the argument representing, the
-// slot where the return value of the function must go.
-pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
-                           -> ValueRef {
+// Creates the alloca slot which holds the pointer to the slot for the final return value
+pub fn make_return_slot_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef {
+    let lloutputtype = type_of::type_of(fcx.ccx, output_type);
+
+    // Let's create the stack slot
+    let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr");
+
+    // and if we're using an out pointer, then store that in our newly made slot
     if type_of::return_uses_outptr(fcx.ccx, output_type) {
-        get_param(fcx.llfn, 0)
-    } else {
-        let lloutputtype = type_of::type_of(fcx.ccx, output_type);
-        AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
+        let outptr = get_param(fcx.llfn, 0);
+
+        let b = fcx.ccx.builder();
+        b.position_before(fcx.alloca_insert_pt.get().unwrap());
+        b.store(outptr, slot);
     }
+
+    slot
 }
 
 // NB: must keep 4 fns in sync:
@@ -1258,7 +1265,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
     let mut fcx = FunctionContext {
           llfn: llfndecl,
           llenv: None,
-          llretptr: Cell::new(None),
+          llretslotptr: Cell::new(None),
           alloca_insert_pt: Cell::new(None),
           llreturn: Cell::new(None),
           personality: Cell::new(None),
@@ -1303,12 +1310,12 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
 
     if !return_type_is_void(fcx.ccx, substd_output_type) {
         // If the function returns nil/bot, there is no real return
-        // value, so do not set `llretptr`.
+        // value, so do not set `llretslotptr`.
         if !skip_retptr || fcx.caller_expects_out_pointer {
-            // Otherwise, we normally allocate the llretptr, unless we
+            // Otherwise, we normally allocate the llretslotptr, unless we
             // have been instructed to skip it for immediate return
             // values.
-            fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
+            fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
         }
     }
 
@@ -1533,12 +1540,12 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
 
 // Builds the return block for a function.
 pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
-    // Return the value if this function immediate; otherwise, return void.
-    if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
+    if fcx.llretslotptr.get().is_none() {
         return RetVoid(ret_cx);
     }
 
-    let retptr = Value(fcx.llretptr.get().unwrap());
+    let retslot = Load(ret_cx, fcx.llretslotptr.get().unwrap());
+    let retptr = Value(retslot);
     let retval = match retptr.get_dominating_store(ret_cx) {
         // If there's only a single store to the ret slot, we can directly return
         // the value that was stored and omit the store and the alloca
@@ -1557,10 +1564,15 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
             }
         }
         // Otherwise, load the return value from the ret slot
-        None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
+        None => load_ty(ret_cx, retslot, retty)
     };
 
-    Ret(ret_cx, retval);
+    if fcx.caller_expects_out_pointer {
+        store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
+        RetVoid(ret_cx);
+    } else {
+        Ret(ret_cx, retval);
+    }
 }
 
 #[deriving(Clone, Eq, PartialEq)]
@@ -1658,10 +1670,10 @@ pub fn trans_closure(ccx: &CrateContext,
     // emitting should be enabled.
     debuginfo::start_emitting_source_locations(&fcx);
 
-    let dest = match fcx.llretptr.get() {
-        Some(e) => {expr::SaveIn(e)}
+    let dest = match fcx.llretslotptr.get() {
+        Some(_) => expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), block_ty), "iret_slot")),
         None => {
-            assert!(type_is_zero_size(bcx.ccx(), block_ty))
+            assert!(type_is_zero_size(bcx.ccx(), block_ty));
             expr::Ignore
         }
     };
@@ -1672,6 +1684,13 @@ pub fn trans_closure(ccx: &CrateContext,
     // (trans_block, trans_expr, et cetera).
     bcx = controlflow::trans_block(bcx, body, dest);
 
+    match dest {
+        expr::SaveIn(slot) => {
+            Store(bcx, slot, fcx.llretslotptr.get().unwrap());
+        }
+        _ => {}
+    }
+
     match fcx.llreturn.get() {
         Some(_) => {
             Br(bcx, fcx.return_exit_block());
@@ -1841,16 +1860,18 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
     let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
 
     if !type_is_zero_size(fcx.ccx, result_ty) {
+        let dest = alloca(bcx, type_of::type_of(bcx.ccx(), result_ty), "eret_slot");
         let repr = adt::represent_type(ccx, result_ty);
         for (i, arg_datum) in arg_datums.move_iter().enumerate() {
             let lldestptr = adt::trans_field_ptr(bcx,
                                                  &*repr,
-                                                 fcx.llretptr.get().unwrap(),
+                                                 dest,
                                                  disr,
                                                  i);
             arg_datum.store_to(bcx, lldestptr);
         }
-        adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
+        adt::trans_set_discr(bcx, &*repr, dest, disr);
+        Store(bcx, dest, fcx.llretslotptr.get().unwrap());
     }
 
     finish_fn(&fcx, bcx, result_ty);
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index f186af48321..3bea9d64462 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -389,6 +389,10 @@ pub fn trans_unboxing_shim(bcx: &Block,
     for i in range(1, arg_types.len()) {
         llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
     }
+    let dest = match fcx.llretslotptr.get() {
+        Some(_) => Some(expr::SaveIn(alloca(bcx, type_of::type_of(ccx, return_type), "ret_slot"))),
+        None => None
+    };
     bcx = trans_call_inner(bcx,
                            None,
                            function_type,
@@ -399,10 +403,13 @@ pub fn trans_unboxing_shim(bcx: &Block,
                                }
                            },
                            ArgVals(llshimmedargs.as_slice()),
-                           match fcx.llretptr.get() {
-                               None => None,
-                               Some(llretptr) => Some(expr::SaveIn(llretptr)),
-                           }).bcx;
+                           dest).bcx;
+    match dest {
+        Some(expr::SaveIn(slot)) => {
+            Store(bcx, slot, fcx.llretslotptr.get().unwrap());
+        }
+        _ => {}
+    }
 
     bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
     finish_fn(&fcx, bcx, return_type);
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index 98b2ebb70f3..dc77edf2706 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -582,16 +582,16 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
                                          ty::ty_fn_args(closure_ty)
                                             .as_slice());
     let mut llargs = Vec::new();
-    match fcx.llretptr.get() {
-        Some(llretptr) => {
-            llargs.push(llretptr);
+    match fcx.llretslotptr.get() {
+        Some(llretslotptr) => {
+            llargs.push(Load(bcx, llretslotptr));
         }
         None => {}
     }
     llargs.extend(args.iter().map(|arg| arg.val));
 
     let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
-    if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
+    if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
         RetVoid(bcx);
     } else {
         Ret(bcx, retval);
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 84f380e862a..6aca8fe8e41 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -240,11 +240,11 @@ pub struct FunctionContext<'a> {
     // The environment argument in a closure.
     pub llenv: Option<ValueRef>,
 
-    // The place to store the return value. If the return type is immediate,
-    // this is an alloca in the function. Otherwise, it's the hidden first
-    // parameter to the function. After function construction, this should
-    // always be Some.
-    pub llretptr: Cell<Option<ValueRef>>,
+    // A pointer to where to store the return value. If the return type is
+    // immediate, this points to an alloca in the function. Otherwise, it's a
+    // pointer to the hidden first parameter of the function. After function
+    // construction, this should always be Some.
+    pub llretslotptr: Cell<Option<ValueRef>>,
 
     // These pub elements: "hoisted basic blocks" containing
     // administrative activities that have to happen in only one place in
@@ -259,8 +259,8 @@ pub struct FunctionContext<'a> {
     pub personality: Cell<Option<ValueRef>>,
 
     // True if the caller expects this fn to use the out pointer to
-    // return. Either way, your code should write into llretptr, but if
-    // this value is false, llretptr will be a local alloca.
+    // return. Either way, your code should write into the slot llretslotptr
+    // points to, but if this value is false, that slot will be a local alloca.
     pub caller_expects_out_pointer: bool,
 
     // Maps arguments to allocas created for them in llallocas.
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 2fd2e69cfc3..b9644b11453 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -26,6 +26,7 @@ use middle::trans::debuginfo;
 use middle::trans::expr;
 use middle::trans::meth;
 use middle::trans::type_::Type;
+use middle::trans::type_of;
 use middle::ty;
 use middle::typeck::MethodCall;
 use util::ppaux::Repr;
@@ -462,13 +463,22 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
     let _icx = push_ctxt("trans_ret");
     let fcx = bcx.fcx;
     let mut bcx = bcx;
-    let dest = match bcx.fcx.llretptr.get() {
-        None => expr::Ignore,
-        Some(retptr) => expr::SaveIn(retptr),
+    let dest = match (fcx.llretslotptr.get(), e) {
+        (Some(_), Some(e)) => {
+            let ret_ty = expr_ty(bcx, &*e);
+            expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), ret_ty), "ret_slot"))
+        }
+        _ => expr::Ignore,
     };
     match e {
         Some(x) => {
             bcx = expr::trans_into(bcx, &*x, dest);
+            match dest {
+                expr::SaveIn(slot) => {
+                    Store(bcx, slot, fcx.llretslotptr.get().unwrap());
+                }
+                _ => {}
+            }
         }
         _ => {}
     }
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index eb0d77da551..35ac0b27071 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -321,7 +321,9 @@ impl<'a, 'b> Reflector<'a, 'b> {
                 let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
                 let arg = BitCast(bcx, arg, llptrty);
                 let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
-                Store(bcx, ret, fcx.llretptr.get().unwrap());
+                let ret_alloca = alloca(bcx, Type::i64(ccx), "ret_slot");
+                Store(bcx, ret, ret_alloca);
+                Store(bcx, ret_alloca, fcx.llretslotptr.get().unwrap());
                 match fcx.llreturn.get() {
                     Some(llreturn) => Br(bcx, llreturn),
                     None => {}