about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2015-12-15 12:20:49 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2016-01-06 13:57:47 +0200
commit6f18b559dfbfde2677fc2b1450fdcbc5c2a5566a (patch)
treea2dd432b37108e5feea6006068501384c6f84b7a
parent893a66d7a11150615c385a190d0140f0b8549409 (diff)
Generate DivergingCall terminator
This simplifies CFG greatly for some cases :)
-rw-r--r--src/librustc_mir/build/expr/into.rs29
-rw-r--r--src/librustc_mir/hair/cx/expr.rs10
-rw-r--r--src/librustc_mir/hair/mod.rs3
3 files changed, 30 insertions, 12 deletions
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 4a262196d36..a173018b74f 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -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()
             }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index aa6257345fe..012bd9691be 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -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,
     }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 6363ddf1e14..fb81cc7e6d9 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -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>>,
     },