Skip to content

Commit 4bd32cf

Browse files
committed
Improve handling of function calls with immediate returns
This fixes up calling foreign functions so they return the value the function returns, same as other calls. It also refactors the as-datum function-call code to handle more cases and to be in a better place.
1 parent 9c0b97d commit 4bd32cf

File tree

4 files changed

+82
-40
lines changed

4 files changed

+82
-40
lines changed

src/librustc_trans/trans/builder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
718718
pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
719719
self.count_insn("icmp");
720720
unsafe {
721+
assert!(val_ty(lhs) == val_ty(rhs), "Cannot compare {} and {}",
722+
self.ccx.tn().val_to_string(lhs),
723+
self.ccx.tn().val_to_string(rhs));
721724
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
722725
}
723726
}

src/librustc_trans/trans/callee.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,13 +860,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
860860
abi);
861861
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
862862

863-
bcx = foreign::trans_native_call(bcx,
863+
let (llret, b) = foreign::trans_native_call(bcx,
864864
callee_ty,
865865
llfn,
866866
opt_llretslot.unwrap(),
867867
&llargs[..],
868868
arg_tys,
869869
debug_loc);
870+
871+
bcx = b;
872+
match (opt_llretslot, ret_ty) {
873+
(Some(_), ty::FnConverging(ret_ty)) => {
874+
if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
875+
!common::type_is_zero_size(bcx.ccx(), ret_ty)
876+
{
877+
llresult = llret;
878+
}
879+
}
880+
(_, _) => {}
881+
}
870882
}
871883

872884
fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);

src/librustc_trans/trans/expr.rs

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ use util::ppaux::Repr;
8282
use trans::machine::{llsize_of, llsize_of_alloc};
8383
use trans::type_::Type;
8484

85-
use syntax::abi as synabi;
8685
use syntax::{ast, ast_util, codemap};
8786
use syntax::parse::token::InternedString;
8887
use syntax::ptr::P;
@@ -580,42 +579,7 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
580579

581580
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
582581

583-
match expr.node {
584-
ast::ExprCall(ref f, ref args) if !bcx.tcx().is_method_call(expr.id) => {
585-
if let ast::ExprPath(..) = f.node {
586-
let fn_ty = expr_ty_adjusted(bcx, f);
587-
let (fty, ret_ty) = match fn_ty.sty {
588-
ty::TyBareFn(_, ref fty) => {
589-
(fty, ty::erase_late_bound_regions(bcx.tcx(), &fty.sig.output()))
590-
}
591-
_ => panic!("Not calling a function?!")
592-
};
593-
594-
if let ty::FnConverging(ret_ty) = ret_ty {
595-
let is_rust_fn = fty.abi == synabi::Rust ||
596-
fty.abi == synabi::RustIntrinsic;
597-
598-
let needs_drop = type_needs_drop(bcx.tcx(), ret_ty);
599-
let uses_output = type_of::return_uses_outptr(bcx.ccx(), ret_ty);
600-
601-
if is_rust_fn && !uses_output && !needs_drop {
602-
let args = callee::ArgExprs(&args[..]);
603-
let result = callee::trans_call_inner(bcx,
604-
expr.debug_loc(),
605-
fn_ty,
606-
|cx, _| callee::trans(cx, f),
607-
args, Some(Ignore));
608-
609-
return immediate_rvalue_bcx(result.bcx, result.val, ret_ty)
610-
.to_expr_datumblock();
611-
}
612-
}
613-
}
614-
}
615-
_ => {}
616-
}
617-
618-
return match ty::expr_kind(bcx.tcx(), expr) {
582+
return match expr_kind(bcx, expr) {
619583
ty::LvalueExpr | ty::RvalueDatumExpr => {
620584
let datum = unpack_datum!(bcx, {
621585
trans_datum_unadjusted(bcx, expr)
@@ -664,6 +628,39 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
664628
}
665629
}
666630

631+
// Get the appropriate expression kind for the expression. Most of the time this just uses
632+
// ty::expr_kind, but `ExprCall`s can be treated as `RvalueDatumExpr`s in some cases.
633+
fn expr_kind<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) -> ty::ExprKind {
634+
match expr.node {
635+
ast::ExprCall(ref f, _) if !bcx.tcx().is_method_call(expr.id) => {
636+
if let ast::ExprPath(..) = f.node {
637+
let fn_ty = expr_ty_adjusted(bcx, f);
638+
639+
let ret_ty = match fn_ty.sty {
640+
ty::TyBareFn(_, ref fty) =>
641+
ty::erase_late_bound_regions(bcx.tcx(), &fty.sig.output()),
642+
_ => bcx.tcx().sess.bug("Not calling a function?")
643+
};
644+
645+
let is_datum = if let ty::FnConverging(output) = ret_ty {
646+
!type_of::return_uses_outptr(bcx.ccx(), output) &&
647+
!bcx.fcx.type_needs_drop(output)
648+
} else {
649+
true
650+
};
651+
652+
653+
if is_datum {
654+
return ty::RvalueDatumExpr;
655+
}
656+
}
657+
}
658+
_ => ()
659+
}
660+
661+
return ty::expr_kind(bcx.tcx(), expr);
662+
}
663+
667664
fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
668665
expr: &ast::Expr)
669666
-> DatumBlock<'blk, 'tcx, Expr> {
@@ -731,6 +728,35 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
731728
// Datum output mode means this is a scalar cast:
732729
trans_imm_cast(bcx, &**val, expr.id)
733730
}
731+
ast::ExprCall(ref f, ref args) => {
732+
let fn_ty = expr_ty_adjusted(bcx, f);
733+
734+
let ret_ty = match fn_ty.sty {
735+
ty::TyBareFn(_, ref fty) => {
736+
ty::erase_late_bound_regions(bcx.tcx(), &fty.sig.output())
737+
}
738+
_ => panic!("Not calling a function?!")
739+
};
740+
741+
let args = callee::ArgExprs(&args[..]);
742+
let result = callee::trans_call_inner(bcx,
743+
expr.debug_loc(),
744+
fn_ty,
745+
|cx, _| callee::trans(cx, f),
746+
args, Some(Ignore));
747+
748+
if let ty::FnConverging(ret_ty) = ret_ty {
749+
immediate_rvalue_bcx(result.bcx, result.val, ret_ty)
750+
.to_expr_datumblock()
751+
} else {
752+
// We called a diverging function, generate an undef value of the appropriate
753+
// type.
754+
let ty = expr_ty(bcx, expr);
755+
let llval = C_undef(type_of::arg_type_of(bcx.ccx(), ty));
756+
let datum = immediate_rvalue(llval, ty);
757+
DatumBlock::new(bcx, datum.to_expr_datum())
758+
}
759+
}
734760
_ => {
735761
bcx.tcx().sess.span_bug(
736762
expr.span,

src/librustc_trans/trans/foreign.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
230230
llargs_rust: &[ValueRef],
231231
passed_arg_tys: Vec<Ty<'tcx>>,
232232
call_debug_loc: DebugLoc)
233-
-> Block<'blk, 'tcx>
233+
-> (ValueRef, Block<'blk, 'tcx>)
234234
{
235235
let ccx = bcx.ccx();
236236
let tcx = bcx.tcx();
@@ -389,6 +389,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
389389
// type to match because some ABIs will use a different type than
390390
// the Rust type. e.g., a {u32,u32} struct could be returned as
391391
// u64.
392+
let llretval = llforeign_retval;
392393
if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
393394
let llrust_ret_ty = llsig.llret_ty;
394395
let llforeign_ret_ty = match fn_type.ret_ty.cast {
@@ -436,7 +437,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
436437
}
437438
}
438439

439-
return bcx;
440+
return (llretval, bcx);
440441
}
441442

442443
// feature gate SIMD types in FFI, since I (huonw) am not sure the

0 commit comments

Comments
 (0)