about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/mir_map.rs3
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs4
-rw-r--r--src/librustc_trans/trans/common.rs4
-rw-r--r--src/librustc_trans/trans/mir/block.rs97
-rw-r--r--src/test/run-fail/mir_drop_panics.rs1
-rw-r--r--src/test/run-fail/mir_trans_calls_converging_drops.rs1
-rw-r--r--src/test/run-fail/mir_trans_calls_converging_drops_2.rs1
-rw-r--r--src/test/run-fail/mir_trans_calls_diverging_drops.rs1
8 files changed, 80 insertions, 32 deletions
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 8f786df3891..5b887db7ec0 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -148,9 +148,6 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
 
         match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
             Ok(mut mir) => {
-                // FIXME: This should run later rather than earlier (since this is supposed to be a
-                // codegen option), but we do not want to re-run the whole simplify_cfg pass all
-                // over again after this pass.
                 no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
                 simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
 
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index 0d5b0630cd2..d0ea9f10f2e 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -26,7 +26,9 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
             Terminator::Return |
             Terminator::If { .. } |
             Terminator::Switch { .. } |
-            Terminator::SwitchInt { .. } => { /* nothing to do */ },
+            Terminator::SwitchInt { .. } => {
+                /* nothing to do */
+            },
             Terminator::Drop { ref mut unwind, .. } => {
                 unwind.take();
             },
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 1269c266c7c..ca370529918 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -767,6 +767,10 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
     {
         self.bcx.monomorphize(value)
     }
+
+    pub fn set_lpad(&self, lpad: Option<LandingPad>) {
+        self.bcx.lpad.set(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
+    }
 }
 
 impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
index ebb3492f962..b5e09cb9c80 100644
--- a/src/librustc_trans/trans/mir/block.rs
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{BasicBlockRef, ValueRef};
+use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
 use rustc::middle::ty;
 use rustc::mir::repr as mir;
 use syntax::abi::Abi;
@@ -34,6 +34,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         let mut bcx = self.bcx(bb);
         let data = self.mir.basic_block_data(bb);
 
+        // MSVC SEH bits
+        let (cleanup_pad, cleanup_bundle) = if let Some((cp, cb)) = self.make_cleanup_pad(bb) {
+            (Some(cp), Some(cb))
+        } else {
+            (None, None)
+        };
+        let funclet_br = |bcx: BlockAndBuilder, llbb: BasicBlockRef| if let Some(cp) = cleanup_pad {
+            bcx.cleanup_ret(cp, Some(llbb));
+        } else {
+            bcx.br(llbb);
+        };
+
         for statement in &data.statements {
             bcx = self.trans_statement(bcx, statement);
         }
@@ -41,8 +53,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         debug!("trans_block: terminator: {:?}", data.terminator());
 
         match *data.terminator() {
+            mir::Terminator::Resume => {
+                if let Some(cleanup_pad) = cleanup_pad {
+                    bcx.cleanup_ret(cleanup_pad, None);
+                } else {
+                    let ps = self.get_personality_slot(&bcx);
+                    let lp = bcx.load(ps);
+                    bcx.with_block(|bcx| {
+                        base::call_lifetime_end(bcx, ps);
+                        base::trans_unwind_resume(bcx, lp);
+                    });
+                }
+            }
+
             mir::Terminator::Goto { target } => {
-                bcx.br(self.llblock(target));
+                funclet_br(bcx, self.llblock(target));
             }
 
             mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
@@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 }
             }
 
-            mir::Terminator::Resume => {
-                let ps = self.get_personality_slot(&bcx);
-                let lp = bcx.load(ps);
-                bcx.with_block(|bcx| {
-                    base::call_lifetime_end(bcx, ps);
-                    base::trans_unwind_resume(bcx, lp);
-                });
-            }
-
             mir::Terminator::Return => {
                 let return_ty = bcx.monomorphize(&self.mir.return_ty);
                 bcx.with_block(|bcx| {
-                    base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
+                    base::build_return_block(self.fcx, bcx, return_ty, DebugLoc::None);
                 })
             }
 
@@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let ty = lvalue.ty.to_ty(bcx.tcx());
                 // Double check for necessity to drop
                 if !glue::type_needs_drop(bcx.tcx(), ty) {
-                    bcx.br(self.llblock(target));
+                    funclet_br(bcx, self.llblock(target));
                     return;
                 }
                 let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
@@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                &[llvalue],
                                self.llblock(target),
                                unwind.llbb(),
-                               None,
+                               cleanup_bundle.as_ref(),
                                None);
                 } else {
-                    bcx.call(drop_fn, &[llvalue], None, None);
-                    bcx.br(self.llblock(target));
+                    bcx.call(drop_fn, &[llvalue], cleanup_bundle.as_ref(), None);
+                    funclet_br(bcx, self.llblock(target));
                 }
             }
 
@@ -191,14 +207,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                    &llargs[..],
                                    unreachable_blk.llbb,
                                    landingpad.llbb(),
-                                   None,
+                                   cleanup_bundle.as_ref(),
                                    Some(attrs));
                     },
                     (false, &Some(cleanup), &Some((_, success))) => {
                         let cleanup = self.bcx(cleanup);
                         let landingpad = self.make_landing_pad(cleanup);
                         let (target, postinvoke) = if must_copy_dest {
-                            (bcx.fcx().new_block("", None).build(), Some(self.bcx(success)))
+                            (self.fcx.new_block("", None).build(), Some(self.bcx(success)))
                         } else {
                             (self.bcx(success), None)
                         };
@@ -206,7 +222,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                                    &llargs[..],
                                                    target.llbb(),
                                                    landingpad.llbb(),
-                                                   None,
+                                                   cleanup_bundle.as_ref(),
                                                    Some(attrs));
                         if let Some(postinvoketarget) = postinvoke {
                             // We translate the copy into a temporary block. The temporary block is
@@ -242,13 +258,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     },
                     (false, _, &None) => {
-                        bcx.call(callee.immediate(), &llargs[..], None, Some(attrs));
+                        bcx.call(callee.immediate(),
+                                 &llargs[..],
+                                 cleanup_bundle.as_ref(),
+                                 Some(attrs));
                         bcx.unreachable();
                     }
                     (false, _, &Some((_, target))) => {
                         let llret = bcx.call(callee.immediate(),
                                              &llargs[..],
-                                             None,
+                                             cleanup_bundle.as_ref(),
                                              Some(attrs));
                         if must_copy_dest {
                             let (ret_dest, ret_ty) = ret_dest_ty
@@ -257,7 +276,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 base::store_ty(bcx, llret, ret_dest.llval, ret_ty);
                             });
                         }
-                        bcx.br(self.llblock(target));
+                        funclet_br(bcx, self.llblock(target));
                     }
                     // Foreign functions
                     (true, _, destination) => {
@@ -273,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                                        debugloc)
                         });
                         if let Some((_, target)) = *destination {
-                            bcx.br(self.llblock(target));
+                            funclet_br(bcx, self.llblock(target));
                         }
                     },
                 }
@@ -296,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         }
     }
 
+    /// Create a landingpad wrapper around the given Block.
+    ///
+    /// No-op in MSVC SEH scheme.
     fn make_landing_pad(&mut self,
                         cleanup: BlockAndBuilder<'bcx, 'tcx>)
                         -> BlockAndBuilder<'bcx, 'tcx>
     {
-        // FIXME(#30941) this doesn't handle msvc-style exceptions
+        if base::wants_msvc_seh(cleanup.sess()) {
+            return cleanup;
+        }
         let bcx = self.fcx.new_block("cleanup", None).build();
         let ccx = bcx.ccx();
         let llpersonality = self.fcx.eh_personality();
@@ -313,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         bcx
     }
 
+    /// Create prologue cleanuppad instruction under MSVC SEH handling scheme.
+    ///
+    /// Also handles setting some state for the original trans and creating an operand bundle for
+    /// function calls.
+    fn make_cleanup_pad(&mut self, bb: mir::BasicBlock) -> Option<(ValueRef, OperandBundleDef)> {
+        let bcx = self.bcx(bb);
+        let data = self.mir.basic_block_data(bb);
+        let use_funclets = base::wants_msvc_seh(bcx.sess()) && data.is_cleanup;
+        let cleanup_pad = if use_funclets {
+            bcx.set_personality_fn(self.fcx.eh_personality());
+            Some(bcx.cleanup_pad(None, &[]))
+        } else {
+            None
+        };
+        // Set the landingpad global-state for old translator, so it knows about the SEH used.
+        bcx.set_lpad(if let Some(cleanup_pad) = cleanup_pad {
+            Some(common::LandingPad::msvc(cleanup_pad))
+        } else if data.is_cleanup {
+            Some(common::LandingPad::gnu())
+        } else {
+            None
+        });
+        cleanup_pad.map(|f| (f, OperandBundleDef::new("funclet", &[f])))
+    }
+
     fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
         self.unreachable_block.unwrap_or_else(|| {
             let bl = self.fcx.new_block("unreachable", None);
diff --git a/src/test/run-fail/mir_drop_panics.rs b/src/test/run-fail/mir_drop_panics.rs
index df20700e016..1a4330523ba 100644
--- a/src/test/run-fail/mir_drop_panics.rs
+++ b/src/test/run-fail/mir_drop_panics.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 #![feature(rustc_attrs)]
 
-// ignore-msvc: FIXME(#30941)
 // error-pattern:panic 1
 // error-pattern:drop 2
 use std::io::{self, Write};
diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs
index eb399e07d85..5927d802b45 100644
--- a/src/test/run-fail/mir_trans_calls_converging_drops.rs
+++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_attrs)]
 
-// ignore-msvc: FIXME(#30941)
 // error-pattern:converging_fn called
 // error-pattern:0 dropped
 // error-pattern:exit
diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
index df4ead387b9..96a46f47eb5 100644
--- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
+++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_attrs)]
 
-// ignore-msvc: FIXME(#30941)
 // error-pattern:complex called
 // error-pattern:dropped
 // error-pattern:exit
diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs
index cbe8793cceb..89b53b18f06 100644
--- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs
+++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_attrs)]
 
-// ignore-msvc: FIXME(#30941)
 // error-pattern:diverging_fn called
 // error-pattern:0 dropped