diff options
| -rw-r--r-- | src/librustc_trans/mir/block.rs | 122 | ||||
| -rw-r--r-- | src/librustc_trans/mir/lvalue.rs | 4 |
2 files changed, 61 insertions, 65 deletions
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b8417f98565..7234bff4397 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -211,70 +211,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let mut llargs = Vec::with_capacity(arg_count); // Prepare the return value destination - let ret_dest = if let Some((ref d, _)) = *destination { - match *d { - // Handle temporary lvalues, specifically Operand ones, as - // they don't have allocas - mir::Lvalue::Temp(idx) => { - let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), d); - let ret_ty = lvalue_ty.to_ty(bcx.tcx()); - match self.temps[idx as usize] { - TempRef::Lvalue(dest) => { - if fn_ty.ret.is_indirect() { - llargs.push(dest.llval); - ReturnDest::Nothing - } else if fn_ty.ret.is_ignore() { - ReturnDest::Nothing - } else { - ReturnDest::Store(dest.llval) - } - } - TempRef::Operand(None) => { - let is_intrinsic = if let Intrinsic = callee.data { - true - } else { - false - }; - - if fn_ty.ret.is_indirect() { - // Odd, but possible, case, we have an operand temporary, - // but the calling convention has an indirect return. - let tmp = bcx.with_block(|bcx| { - base::alloc_ty(bcx, ret_ty, "tmp_ret") - }); - llargs.push(tmp); - ReturnDest::IndirectOperand(tmp, idx) - } else if is_intrinsic { - // Currently, intrinsics always need a location to store - // the result. so we create a temporary alloca for the - // result - let tmp = bcx.with_block(|bcx| { - base::alloc_ty(bcx, ret_ty, "tmp_ret") - }); - ReturnDest::IndirectOperand(tmp, idx) - } else if fn_ty.ret.is_ignore() { - ReturnDest::Nothing - } else { - ReturnDest::DirectOperand(idx) - } - } - TempRef::Operand(Some(_)) => { - bug!("lvalue temp already assigned to"); - } - } - } - _ => { - let dest = self.trans_lvalue(&bcx, d); - if fn_ty.ret.is_indirect() { - llargs.push(dest.llval); - ReturnDest::Nothing - } else if fn_ty.ret.is_ignore() { - ReturnDest::Nothing - } else { - ReturnDest::Store(dest.llval) - } - } - } + let ret_dest = if let Some((ref dest, _)) = *destination { + let is_intrinsic = if let Intrinsic = callee.data { + true + } else { + false + }; + self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, is_intrinsic) } else { ReturnDest::Nothing }; @@ -601,6 +544,57 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { self.blocks[bb.index()].llbb } + fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, + dest: &mir::Lvalue<'tcx>, fn_ret_ty: &ArgType, + llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest { + // If the return is ignored, we can just return a do-nothing ReturnDest + if fn_ret_ty.is_ignore() { + return ReturnDest::Nothing; + } + let dest = match *dest { + mir::Lvalue::Temp(idx) => { + let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), dest); + let ret_ty = lvalue_ty.to_ty(bcx.tcx()); + match self.temps[idx as usize] { + TempRef::Lvalue(dest) => dest, + TempRef::Operand(None) => { + // Handle temporary lvalues, specifically Operand ones, as + // they don't have allocas + return if fn_ret_ty.is_indirect() { + // Odd, but possible, case, we have an operand temporary, + // but the calling convention has an indirect return. + let tmp = bcx.with_block(|bcx| { + base::alloc_ty(bcx, ret_ty, "tmp_ret") + }); + llargs.push(tmp); + ReturnDest::IndirectOperand(tmp, idx) + } else if is_intrinsic { + // Currently, intrinsics always need a location to store + // the result. so we create a temporary alloca for the + // result + let tmp = bcx.with_block(|bcx| { + base::alloc_ty(bcx, ret_ty, "tmp_ret") + }); + ReturnDest::IndirectOperand(tmp, idx) + } else { + ReturnDest::DirectOperand(idx) + }; + } + TempRef::Operand(Some(_)) => { + bug!("lvalue temp already assigned to"); + } + } + } + _ => self.trans_lvalue(bcx, dest) + }; + if fn_ret_ty.is_indirect() { + llargs.push(dest.llval); + ReturnDest::Nothing + } else { + ReturnDest::Store(dest.llval) + } + } + fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) { let mut val = self.trans_operand(bcx, src); diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 5a0992a6b6b..13e1894df16 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -220,7 +220,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { TempRef::Lvalue(lvalue) => f(self, lvalue), TempRef::Operand(None) => { let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue); - let lvalue = LvalueRef::alloca(bcx, lvalue_ty.to_ty(bcx.tcx()), "lvalue_temp"); + let lvalue = LvalueRef::alloca(bcx, + lvalue_ty.to_ty(bcx.tcx()), + "lvalue_temp"); let ret = f(self, lvalue); let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx())); self.temps[idx as usize] = TempRef::Operand(Some(op)); |
