diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 9b6613e4cae96..362053eddd39f 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -54,6 +54,7 @@ for mir::Terminator<'gcx> { mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume | + mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable | @@ -148,6 +149,7 @@ for mir::TerminatorKind<'gcx> { targets.hash_stable(hcx, hasher); } mir::TerminatorKind::Resume | + mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable => {} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d43504b77ba0c..e46881408b3da 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -575,6 +575,10 @@ pub enum TerminatorKind<'tcx> { /// continue. Emitted by build::scope::diverge_cleanup. Resume, + /// Indicates that the landing pad is finished and that the process + /// should abort. Used to prevent unwinding for foreign items. + Abort, + /// Indicates a normal return. The return pointer lvalue should /// have been filled in by now. This should occur at most once. Return, @@ -660,7 +664,7 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Goto { target: ref b } => slice::ref_slice(b).into_cow(), SwitchInt { targets: ref b, .. } => b[..].into_cow(), - Resume | GeneratorDrop => (&[]).into_cow(), + Resume | Abort | GeneratorDrop => (&[]).into_cow(), Return => (&[]).into_cow(), Unreachable => (&[]).into_cow(), Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), @@ -690,7 +694,7 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Goto { target: ref mut b } => vec![b], SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), - Resume | GeneratorDrop => Vec::new(), + Resume | Abort | GeneratorDrop => Vec::new(), Return => Vec::new(), Unreachable => Vec::new(), Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], @@ -780,6 +784,7 @@ impl<'tcx> TerminatorKind<'tcx> { Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), + Abort => write!(fmt, "abort"), Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), Unreachable => write!(fmt, "unreachable"), Drop { ref location, .. } => write!(fmt, "drop({:?})", location), @@ -831,7 +836,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec> { use self::TerminatorKind::*; match *self { - Return | Resume | Unreachable | GeneratorDrop => vec![], + Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref values, .. } => { values.iter() @@ -1806,6 +1811,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }, GeneratorDrop => GeneratorDrop, Resume => Resume, + Abort => Abort, Return => Return, Unreachable => Unreachable, }; @@ -1845,6 +1851,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }, Goto { .. } | Resume | + Abort | Return | GeneratorDrop | Unreachable => false diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 37c97ad3dad90..8276b98f7c0e8 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -431,6 +431,7 @@ macro_rules! make_mir_visitor { } TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 063cbc7755915..675c1865493c4 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -291,6 +291,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index be6f8c9e56c40..71f3a19fa179a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -378,10 +378,27 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id); let mut block = START_BLOCK; let source_info = builder.source_info(span); + unpack!(block = builder.in_scope((call_site_scope, source_info), block, |builder| { + + // According to rustc_trans/callee we mark all foreign instances with nounwind, + // so let's make sure we don't unwind. + // Therefore generate an extra "Abort" landing pad. + + // This does not work :-( + // let is_foreign = tcx.is_foreign_item(tcx.hir.local_def_id(fn_id)); + let is_foreign = match abi { + Abi::Rust | Abi::RustCall | Abi::RustIntrinsic => false, + _ => true, + }; + if is_foreign && !tcx.sess.no_landing_pads() { + builder.schedule_abort(); + }; + unpack!(block = builder.in_scope((arg_scope, source_info), block, |builder| { builder.args_and_body(block, &arguments, arg_scope, &body.value) })); + // Attribute epilogue to function's closing brace let fn_end = span.with_lo(span.hi()); let source_info = builder.source_info(fn_end); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index bac884b4d01e9..cf54a2c28cef9 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -563,6 +563,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + pub fn schedule_abort(&mut self) -> BasicBlock { + self.scopes[0].needs_cleanup = true; + let abortblk = self.cfg.start_new_cleanup_block(); + self.cfg.terminate(abortblk, self.scopes[0].source_info(self.fn_span), TerminatorKind::Abort); + self.cached_resume_block = Some(abortblk); + abortblk + } + // Scheduling drops // ================ /// Indicates that `lvalue` should be dropped on exit from diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 9fa5691d647b7..32eee8b300e46 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -676,6 +676,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation { match bb_data.terminator().kind { mir::TerminatorKind::Return | + mir::TerminatorKind::Abort | mir::TerminatorKind::Resume | mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable => {} diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 86298c3b83e29..3ed807e442190 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -263,6 +263,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 48a21dfdbd467..421dd0b355791 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -713,6 +713,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *kind = TerminatorKind::Goto { target: tgt } } } + TerminatorKind::Abort => { + unimplemented!("I assume here's where we're supposed to insert a call to intrinsics::abort?"); + } TerminatorKind::Unreachable => { } } } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index fa6bb644871dc..4cfaa06854157 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -41,6 +41,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { match terminator.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 3f3b9d177d70c..9a0461868bc7a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -315,6 +315,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::Unreachable => None, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index ab5998a34805b..e22474bceea1d 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -438,6 +438,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match term.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | + TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | @@ -643,6 +644,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, block, "resume on non-cleanup block!") } } + TerminatorKind::Abort => { + if !is_cleanup { + span_mirbug!(self, block, "abort on non-cleanup block!") + } + } TerminatorKind::Return => { if is_cleanup { span_mirbug!(self, block, "return on cleanup block") diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 1fa49614580a3..4c72170810bce 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { TerminatorKind::Goto { .. } => "TerminatorKind::Goto", TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", TerminatorKind::Resume => "TerminatorKind::Resume", + TerminatorKind::Abort => "TerminatorKind::Abort", TerminatorKind::Return => "TerminatorKind::Return", TerminatorKind::Unreachable => "TerminatorKind::Unreachable", TerminatorKind::Drop { .. } => "TerminatorKind::Drop", diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 6fa69de74b0a1..3854210c0cd95 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -615,6 +615,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume | + mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable | mir::TerminatorKind::Assert { .. } => {} diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 1017ec6b3c3f8..ec9155c05cfec 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -217,6 +217,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec MirContext<'a, 'tcx> { self.set_debug_loc(&bcx, terminator.source_info); match terminator.kind { + mir::TerminatorKind::Abort => { + // Call core::intrinsics::abort() + let fnname = bcx.ccx.get_intrinsic(&("llvm.trap")); + bcx.call(fnname, &[], None); + bcx.unreachable(); + } + mir::TerminatorKind::Resume => { if let Some(cleanup_pad) = cleanup_pad { bcx.cleanup_ret(cleanup_pad, None);