Generate DivergingCall terminator

This simplifies CFG greatly for some cases :)
This commit is contained in:
Simonas Kazlauskas 2015-12-15 12:20:49 +02:00
parent 893a66d7a1
commit 6f18b559df
3 changed files with 30 additions and 12 deletions

View File

@ -15,6 +15,7 @@ use build::expr::category::{Category, RvalueFunc};
use build::scope::LoopScope;
use hair::*;
use rustc::middle::region::CodeExtent;
use rustc::middle::ty;
use rustc::mir::repr::*;
use syntax::codemap::Span;
@ -210,22 +211,30 @@ impl<'a,'tcx> Builder<'a,'tcx> {
this.exit_scope(expr_span, extent, block, END_BLOCK);
this.cfg.start_new_block().unit()
}
ExprKind::Call { fun, args } => {
ExprKind::Call { ty, fun, args } => {
let diverges = match ty.sty {
ty::TyBareFn(_, ref f) => f.sig.0.output.diverges(),
_ => false
};
let fun = unpack!(block = this.as_operand(block, fun));
let args: Vec<_> =
args.into_iter()
.map(|arg| unpack!(block = this.as_operand(block, arg)))
.collect();
let success = this.cfg.start_new_block();
let panic = this.diverge_cleanup();
let targets = CallTargets::WithCleanup((success, panic));
this.cfg.terminate(block,
Terminator::Call {
func: fun,
args: args,
destination: destination.clone(),
targets: targets
});
let cleanup = this.diverge_cleanup();
let term = if diverges {
Terminator::DivergingCall { func: fun, args: args, cleanup: Some(cleanup) }
} else {
Terminator::Call {
func: fun,
args: args,
destination: destination.clone(),
targets: CallTargets::WithCleanup((success, cleanup))
}
};
this.cfg.terminate(block, term);
success.unit()
}

View File

@ -41,6 +41,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
.map(|e| e.to_ref())
.collect();
ExprKind::Call {
ty: expr.ty,
fun: expr.to_ref(),
args: args,
}
@ -58,11 +59,17 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
argrefs.extend(args.iter().map(|a| a.to_ref()));
ExprKind::Call {
ty: method.ty,
fun: method.to_ref(),
args: argrefs,
}
} else {
ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() }
ExprKind::Call {
ty: &cx.tcx.node_id_to_type(fun.id),
fun: fun.to_ref(),
args: args.to_ref(),
}
}
}
@ -802,6 +809,7 @@ fn overloaded_operator<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
// now create the call itself
let fun = method_callee(cx, expr, method_call);
ExprKind::Call {
ty: fun.ty,
fun: fun.to_ref(),
args: argrefs,
}

View File

@ -19,7 +19,7 @@ use rustc::middle::const_eval::ConstVal;
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
use rustc::middle::subst::Substs;
use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
use rustc::middle::ty::{self, AdtDef, ClosureSubsts, Region, Ty};
use rustc_front::hir;
use syntax::ast;
use syntax::codemap::Span;
@ -124,6 +124,7 @@ pub enum ExprKind<'tcx> {
value: ExprRef<'tcx>,
},
Call {
ty: ty::Ty<'tcx>,
fun: ExprRef<'tcx>,
args: Vec<ExprRef<'tcx>>,
},