Refactor unwind from Option to a new enum

This commit is contained in:
Gary Guo 2022-10-08 23:47:59 +01:00
parent 7f6edd3f15
commit daeb844e0c
39 changed files with 328 additions and 250 deletions

View file

@ -11,7 +11,7 @@ use crate::{
}; };
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location}; use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_middle::ty::{RegionVid, TyCtxt};
pub(crate) fn find<'tcx>( pub(crate) fn find<'tcx>(
@ -70,7 +70,10 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
block_data block_data
.terminator() .terminator()
.successors() .successors()
.filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind()) .filter(|&bb| {
Some(&mir::UnwindAction::Cleanup(bb))
!= block_data.terminator().unwind()
})
.map(|bb| Location { statement_index: 0, block: bb }), .map(|bb| Location { statement_index: 0, block: bb }),
); );
} }

View file

@ -125,7 +125,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
args, args,
destination, destination,
target: _, target: _,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {
@ -135,7 +135,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
} }
self.mutate_place(location, *destination, Deep); self.mutate_place(location, *destination, Deep);
} }
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => { TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(location, cond); self.consume_operand(location, cond);
use rustc_middle::mir::AssertKind; use rustc_middle::mir::AssertKind;
if let AssertKind::BoundsCheck { len, index } = msg { if let AssertKind::BoundsCheck { len, index } = msg {
@ -173,7 +173,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
options: _, options: _,
line_spans: _, line_spans: _,
destination: _, destination: _,
cleanup: _, unwind: _,
} => { } => {
for op in operands { for op in operands {
match op { match op {

View file

@ -740,7 +740,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
args, args,
destination, destination,
target: _, target: _,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {
@ -750,7 +750,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
} }
self.mutate_place(loc, (*destination, span), Deep, flow_state); self.mutate_place(loc, (*destination, span), Deep, flow_state);
} }
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => { TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(loc, (cond, span), flow_state); self.consume_operand(loc, (cond, span), flow_state);
use rustc_middle::mir::AssertKind; use rustc_middle::mir::AssertKind;
if let AssertKind::BoundsCheck { len, index } = msg { if let AssertKind::BoundsCheck { len, index } = msg {
@ -770,7 +770,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
options: _, options: _,
line_spans: _, line_spans: _,
destination: _, destination: _,
cleanup: _, unwind: _,
} => { } => {
for op in operands { for op in operands {
match op { match op {

View file

@ -1610,20 +1610,20 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
TerminatorKind::Unreachable => {} TerminatorKind::Unreachable => {}
TerminatorKind::Drop { target, unwind, .. } TerminatorKind::Drop { target, unwind, .. }
| TerminatorKind::Assert { target, cleanup: unwind, .. } => { | TerminatorKind::Assert { target, unwind, .. } => {
self.assert_iscleanup(body, block_data, target, is_cleanup); self.assert_iscleanup(body, block_data, target, is_cleanup);
if let Some(unwind) = unwind { if let UnwindAction::Cleanup(unwind) = unwind {
if is_cleanup { if is_cleanup {
span_mirbug!(self, block_data, "unwind on cleanup block") span_mirbug!(self, block_data, "unwind on cleanup block")
} }
self.assert_iscleanup(body, block_data, unwind, true); self.assert_iscleanup(body, block_data, unwind, true);
} }
} }
TerminatorKind::Call { ref target, cleanup, .. } => { TerminatorKind::Call { ref target, unwind, .. } => {
if let &Some(target) = target { if let &Some(target) = target {
self.assert_iscleanup(body, block_data, target, is_cleanup); self.assert_iscleanup(body, block_data, target, is_cleanup);
} }
if let Some(cleanup) = cleanup { if let UnwindAction::Cleanup(cleanup) = unwind {
if is_cleanup { if is_cleanup {
span_mirbug!(self, block_data, "cleanup on cleanup block") span_mirbug!(self, block_data, "cleanup on cleanup block")
} }
@ -1636,18 +1636,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
TerminatorKind::FalseUnwind { real_target, unwind } => { TerminatorKind::FalseUnwind { real_target, unwind } => {
self.assert_iscleanup(body, block_data, real_target, is_cleanup); self.assert_iscleanup(body, block_data, real_target, is_cleanup);
if let Some(unwind) = unwind { if let UnwindAction::Cleanup(unwind) = unwind {
if is_cleanup { if is_cleanup {
span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
} }
self.assert_iscleanup(body, block_data, unwind, true); self.assert_iscleanup(body, block_data, unwind, true);
} }
} }
TerminatorKind::InlineAsm { destination, cleanup, .. } => { TerminatorKind::InlineAsm { destination, unwind, .. } => {
if let Some(target) = destination { if let Some(target) = destination {
self.assert_iscleanup(body, block_data, target, is_cleanup); self.assert_iscleanup(body, block_data, target, is_cleanup);
} }
if let Some(cleanup) = cleanup { if let UnwindAction::Cleanup(cleanup) = unwind {
if is_cleanup { if is_cleanup {
span_mirbug!(self, block_data, "cleanup on cleanup block") span_mirbug!(self, block_data, "cleanup on cleanup block")
} }

View file

@ -345,7 +345,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
TerminatorKind::Return => { TerminatorKind::Return => {
crate::abi::codegen_return(fx); crate::abi::codegen_return(fx);
} }
TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => { TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => {
if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
let target = fx.get_block(*target); let target = fx.get_block(*target);
fx.bcx.ins().jump(target, &[]); fx.bcx.ins().jump(target, &[]);
@ -450,7 +450,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
destination, destination,
target, target,
fn_span, fn_span,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
} => { } => {
fx.tcx.prof.generic_activity("codegen call").run(|| { fx.tcx.prof.generic_activity("codegen call").run(|| {
@ -470,7 +470,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
options, options,
destination, destination,
line_spans: _, line_spans: _,
cleanup: _, unwind: _,
} => { } => {
if options.contains(InlineAsmOptions::MAY_UNWIND) { if options.contains(InlineAsmOptions::MAY_UNWIND) {
fx.tcx.sess.span_fatal( fx.tcx.sess.span_fatal(

View file

@ -292,11 +292,11 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
| TerminatorKind::Yield { .. } | TerminatorKind::Yield { .. }
| TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ } | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
TerminatorKind::Call { cleanup: unwind, .. } TerminatorKind::Call { unwind, .. }
| TerminatorKind::InlineAsm { cleanup: unwind, .. } | TerminatorKind::InlineAsm { unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. } | TerminatorKind::Assert { unwind, .. }
| TerminatorKind::Drop { unwind, .. } => { | TerminatorKind::Drop { unwind, .. } => {
if let Some(unwind) = unwind { if let mir::UnwindAction::Cleanup(unwind) = unwind {
debug!( debug!(
"cleanup_kinds: {:?}/{:?} registering {:?} as funclet", "cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
bb, data, unwind bb, data, unwind

View file

@ -156,7 +156,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
fn_ptr: Bx::Value, fn_ptr: Bx::Value,
llargs: &[Bx::Value], llargs: &[Bx::Value],
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>], copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
@ -164,6 +164,10 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
// do an invoke, otherwise do a call. // do an invoke, otherwise do a call.
let fn_ty = bx.fn_decl_backend_type(&fn_abi); let fn_ty = bx.fn_decl_backend_type(&fn_abi);
let cleanup = match unwind {
mir::UnwindAction::Cleanup(cleanup) => Some(cleanup),
mir::UnwindAction::Continue => None,
};
let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) { let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
Some(self.llbb_with_cleanup(fx, cleanup)) Some(self.llbb_with_cleanup(fx, cleanup))
} else if fx.mir[self.bb].is_cleanup } else if fx.mir[self.bb].is_cleanup
@ -244,11 +248,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
options: InlineAsmOptions, options: InlineAsmOptions,
line_spans: &[Span], line_spans: &[Span],
destination: Option<mir::BasicBlock>, destination: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
instance: Instance<'_>, instance: Instance<'_>,
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
if let Some(cleanup) = cleanup { if let mir::UnwindAction::Cleanup(cleanup) = unwind {
let ret_llbb = if let Some(target) = destination { let ret_llbb = if let Some(target) = destination {
fx.llbb(target) fx.llbb(target)
} else { } else {
@ -431,7 +435,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &mut Bx, bx: &mut Bx,
location: mir::Place<'tcx>, location: mir::Place<'tcx>,
target: mir::BasicBlock, target: mir::BasicBlock,
unwind: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
let ty = location.ty(self.mir, bx.tcx()).ty; let ty = location.ty(self.mir, bx.tcx()).ty;
@ -552,7 +556,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
expected: bool, expected: bool,
msg: &mir::AssertMessage<'tcx>, msg: &mir::AssertMessage<'tcx>,
target: mir::BasicBlock, target: mir::BasicBlock,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
let span = terminator.source_info.span; let span = terminator.source_info.span;
@ -618,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item); let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
// Codegen the actual panic invoke/call. // Codegen the actual panic invoke/call.
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, cleanup, &[], false); let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
assert_eq!(merging_succ, MergingSucc::False); assert_eq!(merging_succ, MergingSucc::False);
MergingSucc::False MergingSucc::False
} }
@ -636,7 +640,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind); let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
// Codegen the actual panic invoke/call. // Codegen the actual panic invoke/call.
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false); let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, mir::UnwindAction::Continue, &[], false);
assert_eq!(merging_succ, MergingSucc::False); assert_eq!(merging_succ, MergingSucc::False);
} }
@ -649,7 +653,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
instance: Option<Instance<'tcx>>, instance: Option<Instance<'tcx>>,
source_info: mir::SourceInfo, source_info: mir::SourceInfo,
target: Option<mir::BasicBlock>, target: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
mergeable_succ: bool, mergeable_succ: bool,
) -> Option<MergingSucc> { ) -> Option<MergingSucc> {
// Emit a panic or a no-op for `assert_*` intrinsics. // Emit a panic or a no-op for `assert_*` intrinsics.
@ -696,7 +700,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
llfn, llfn,
&[msg.0, msg.1], &[msg.0, msg.1],
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
cleanup, unwind,
&[], &[],
mergeable_succ, mergeable_succ,
) )
@ -719,7 +723,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args: &[mir::Operand<'tcx>], args: &[mir::Operand<'tcx>],
destination: mir::Place<'tcx>, destination: mir::Place<'tcx>,
target: Option<mir::BasicBlock>, target: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
fn_span: Span, fn_span: Span,
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
@ -783,7 +787,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
instance, instance,
source_info, source_info,
target, target,
cleanup, unwind,
mergeable_succ, mergeable_succ,
) { ) {
return merging_succ; return merging_succ;
@ -1064,7 +1068,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_ptr, fn_ptr,
&llargs, &llargs,
target.as_ref().map(|&target| (ret_dest, target)), target.as_ref().map(|&target| (ret_dest, target)),
cleanup, unwind,
&copied_constant_arguments, &copied_constant_arguments,
false, false,
); );
@ -1084,7 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_ptr, fn_ptr,
&llargs, &llargs,
target.as_ref().map(|&target| (ret_dest, target)), target.as_ref().map(|&target| (ret_dest, target)),
cleanup, unwind,
&copied_constant_arguments, &copied_constant_arguments,
mergeable_succ, mergeable_succ,
) )
@ -1100,7 +1104,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options: ast::InlineAsmOptions, options: ast::InlineAsmOptions,
line_spans: &[Span], line_spans: &[Span],
destination: Option<mir::BasicBlock>, destination: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
instance: Instance<'_>, instance: Instance<'_>,
mergeable_succ: bool, mergeable_succ: bool,
) -> MergingSucc { ) -> MergingSucc {
@ -1164,7 +1168,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options, options,
line_spans, line_spans,
destination, destination,
cleanup, unwind,
instance, instance,
mergeable_succ, mergeable_succ,
) )
@ -1274,7 +1278,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
} }
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => self mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
.codegen_assert_terminator( .codegen_assert_terminator(
helper, helper,
bx, bx,
@ -1283,7 +1287,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
expected, expected,
msg, msg,
target, target,
cleanup, unwind,
mergeable_succ(), mergeable_succ(),
), ),
@ -1292,7 +1296,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ref args, ref args,
destination, destination,
target, target,
cleanup, unwind,
from_hir_call: _, from_hir_call: _,
fn_span, fn_span,
} => self.codegen_call_terminator( } => self.codegen_call_terminator(
@ -1303,7 +1307,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args, args,
destination, destination,
target, target,
cleanup, unwind,
fn_span, fn_span,
mergeable_succ(), mergeable_succ(),
), ),
@ -1320,7 +1324,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options, options,
line_spans, line_spans,
destination, destination,
cleanup, unwind,
} => self.codegen_asm_terminator( } => self.codegen_asm_terminator(
helper, helper,
bx, bx,
@ -1330,7 +1334,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options, options,
line_spans, line_spans,
destination, destination,
cleanup, unwind,
self.instance, self.instance,
mergeable_succ(), mergeable_succ(),
), ),

View file

@ -526,7 +526,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
fn assert_panic( fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>, ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &AssertMessage<'tcx>, msg: &AssertMessage<'tcx>,
_unwind: Option<mir::BasicBlock>, _unwind: mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
use rustc_middle::mir::AssertKind::*; use rustc_middle::mir::AssertKind::*;
// Convert `AssertKind<Operand>` to `AssertKind<Scalar>`. // Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.

View file

@ -215,7 +215,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
fn assert_panic( fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>, ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &mir::AssertMessage<'tcx>, msg: &mir::AssertMessage<'tcx>,
unwind: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
) -> InterpResult<'tcx>; ) -> InterpResult<'tcx>;
/// Called to evaluate `Abort` MIR terminator. /// Called to evaluate `Abort` MIR terminator.

View file

@ -60,7 +60,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ref args, ref args,
destination, destination,
target, target,
ref cleanup, ref unwind,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {
@ -106,9 +106,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
with_caller_location, with_caller_location,
&destination, &destination,
target, target,
match (cleanup, fn_abi.can_unwind) { match (unwind, fn_abi.can_unwind) {
(Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), (mir::UnwindAction::Cleanup(cleanup), true) => {
(None, true) => StackPopUnwind::Skip, StackPopUnwind::Cleanup(*cleanup)
}
(mir::UnwindAction::Continue, true) => StackPopUnwind::Skip,
(_, false) => StackPopUnwind::NotAllowed, (_, false) => StackPopUnwind::NotAllowed,
}, },
)?; )?;
@ -137,14 +139,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.drop_in_place(&place, instance, target, unwind)?; self.drop_in_place(&place, instance, target, unwind)?;
} }
Assert { ref cond, expected, ref msg, target, cleanup } => { Assert { ref cond, expected, ref msg, target, unwind } => {
let ignored = let ignored =
M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check(); M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
if ignored || expected == cond_val { if ignored || expected == cond_val {
self.go_to_block(target); self.go_to_block(target);
} else { } else {
M::assert_panic(self, msg, cleanup)?; M::assert_panic(self, msg, unwind)?;
} }
} }
@ -676,7 +678,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
place: &PlaceTy<'tcx, M::Provenance>, place: &PlaceTy<'tcx, M::Provenance>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
target: mir::BasicBlock, target: mir::BasicBlock,
unwind: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
// We take the address of the object. This may well be unaligned, which is fine // We take the address of the object. This may well be unaligned, which is fine
@ -718,8 +720,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&ret.into(), &ret.into(),
Some(target), Some(target),
match unwind { match unwind {
Some(cleanup) => StackPopUnwind::Cleanup(cleanup), mir::UnwindAction::Cleanup(cleanup) => StackPopUnwind::Cleanup(cleanup),
None => StackPopUnwind::Skip, mir::UnwindAction::Continue => StackPopUnwind::Skip,
}, },
) )
} }

View file

@ -807,7 +807,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
kind: TerminatorKind::Call { kind: TerminatorKind::Call {
func, func,
args, args,
cleanup: None, unwind: UnwindAction::Continue,
destination: Place::from(new_temp), destination: Place::from(new_temp),
target: Some(new_target), target: Some(new_target),
from_hir_call, from_hir_call,

View file

@ -10,7 +10,7 @@ use rustc_middle::mir::{
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, UnOp, VarDebugInfo, VarDebugInfoContents, START_BLOCK, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
}; };
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::impls::MaybeStorageLive;
@ -902,11 +902,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
TerminatorKind::Drop { target, unwind, .. } => { TerminatorKind::Drop { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal); self.check_edge(location, *target, EdgeKind::Normal);
if let Some(unwind) = unwind { if let UnwindAction::Cleanup(unwind) = unwind {
self.check_edge(location, *unwind, EdgeKind::Unwind); self.check_edge(location, *unwind, EdgeKind::Unwind);
} }
} }
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => { TerminatorKind::Call { func, args, destination, target, unwind, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx); let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() { match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {} ty::FnPtr(..) | ty::FnDef(..) => {}
@ -918,7 +918,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if let Some(target) = target { if let Some(target) = target {
self.check_edge(location, *target, EdgeKind::Normal); self.check_edge(location, *target, EdgeKind::Normal);
} }
if let Some(cleanup) = cleanup { if let UnwindAction::Cleanup(cleanup) = unwind {
self.check_edge(location, *cleanup, EdgeKind::Unwind); self.check_edge(location, *cleanup, EdgeKind::Unwind);
} }
@ -946,7 +946,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
); );
} }
} }
TerminatorKind::Assert { cond, target, cleanup, .. } => { TerminatorKind::Assert { cond, target, unwind, .. } => {
let cond_ty = cond.ty(&self.body.local_decls, self.tcx); let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
if cond_ty != self.tcx.types.bool { if cond_ty != self.tcx.types.bool {
self.fail( self.fail(
@ -958,7 +958,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
); );
} }
self.check_edge(location, *target, EdgeKind::Normal); self.check_edge(location, *target, EdgeKind::Normal);
if let Some(cleanup) = cleanup { if let UnwindAction::Cleanup(cleanup) = unwind {
self.check_edge(location, *cleanup, EdgeKind::Unwind); self.check_edge(location, *cleanup, EdgeKind::Unwind);
} }
} }
@ -992,15 +992,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
); );
} }
self.check_edge(location, *real_target, EdgeKind::Normal); self.check_edge(location, *real_target, EdgeKind::Normal);
if let Some(unwind) = unwind { if let UnwindAction::Cleanup(unwind) = unwind {
self.check_edge(location, *unwind, EdgeKind::Unwind); self.check_edge(location, *unwind, EdgeKind::Unwind);
} }
} }
TerminatorKind::InlineAsm { destination, cleanup, .. } => { TerminatorKind::InlineAsm { destination, unwind, .. } => {
if let Some(destination) = destination { if let Some(destination) = destination {
self.check_edge(location, *destination, EdgeKind::Normal); self.check_edge(location, *destination, EdgeKind::Normal);
} }
if let Some(cleanup) = cleanup { if let UnwindAction::Cleanup(cleanup) = unwind {
self.check_edge(location, *cleanup, EdgeKind::Unwind); self.check_edge(location, *cleanup, EdgeKind::Unwind);
} }
} }

View file

@ -515,14 +515,14 @@ pub struct CopyNonOverlapping<'tcx> {
/// ///
/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then /// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then
/// once the current function is reached, execution continues at the given basic block, if any. If /// once the current function is reached, an action will be taken based on the `unwind` field.
/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is /// If the action is `Cleanup`, then the execution continues at the given basic block. If the
/// equivalent to the execution of a `Resume` terminator. /// action is `Continue` then no cleanup is performed, and the stack continues unwinding.
/// ///
/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` /// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set.
/// basic blocks have a couple restrictions: /// `cleanup` basic blocks have a couple restrictions:
/// 1. All `cleanup` fields in them must be `None`. /// 1. All `unwind` fields in them must be `UnwindAction::Continue`.
/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. /// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
/// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// must also be `cleanup`. This is a part of the type system and checked statically, so it is
@ -604,7 +604,7 @@ pub enum TerminatorKind<'tcx> {
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
/// > consider indirect assignments. /// > consider indirect assignments.
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
/// the referred to function. The operand types must match the argument types of the function. /// the referred to function. The operand types must match the argument types of the function.
@ -628,8 +628,8 @@ pub enum TerminatorKind<'tcx> {
destination: Place<'tcx>, destination: Place<'tcx>,
/// Where to go after this call returns. If none, the call necessarily diverges. /// Where to go after this call returns. If none, the call necessarily diverges.
target: Option<BasicBlock>, target: Option<BasicBlock>,
/// Cleanups to be done if the call unwinds. /// Action to be taken if the call unwinds.
cleanup: Option<BasicBlock>, unwind: UnwindAction,
/// `true` if this is from a call in HIR rather than from an overloaded /// `true` if this is from a call in HIR rather than from an overloaded
/// operator. True for overloaded function call. /// operator. True for overloaded function call.
from_hir_call: bool, from_hir_call: bool,
@ -654,7 +654,7 @@ pub enum TerminatorKind<'tcx> {
expected: bool, expected: bool,
msg: AssertMessage<'tcx>, msg: AssertMessage<'tcx>,
target: BasicBlock, target: BasicBlock,
cleanup: Option<BasicBlock>, unwind: UnwindAction,
}, },
/// Marks a suspend point. /// Marks a suspend point.
@ -720,9 +720,10 @@ pub enum TerminatorKind<'tcx> {
/// in practice, but in order to avoid fragility we want to always /// in practice, but in order to avoid fragility we want to always
/// consider it in borrowck. We don't want to accept programs which /// consider it in borrowck. We don't want to accept programs which
/// pass borrowck only when `panic=abort` or some assertions are disabled /// pass borrowck only when `panic=abort` or some assertions are disabled
/// due to release vs. debug mode builds. This needs to be an `Option` because /// due to release vs. debug mode builds.
/// This field does not necessary have to be `UnwindAction::Cleanup` because
/// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
unwind: Option<BasicBlock>, unwind: UnwindAction,
}, },
/// Block ends with an inline assembly block. This is a terminator since /// Block ends with an inline assembly block. This is a terminator since
@ -745,12 +746,22 @@ pub enum TerminatorKind<'tcx> {
/// diverging (InlineAsmOptions::NORETURN). /// diverging (InlineAsmOptions::NORETURN).
destination: Option<BasicBlock>, destination: Option<BasicBlock>,
/// Cleanup to be done if the inline assembly unwinds. This is present /// Action to be taken if the inline assembly unwinds. This is present
/// if and only if InlineAsmOptions::MAY_UNWIND is set. /// if and only if InlineAsmOptions::MAY_UNWIND is set.
cleanup: Option<BasicBlock>, unwind: UnwindAction,
}, },
} }
/// Action to be taken when a stack unwind happens.
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum UnwindAction {
// No action is to be taken. Continue unwinding.
Continue,
// Cleanups to be done.
Cleanup(BasicBlock),
}
/// Information about an assertion failure. /// Information about an assertion failure.
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
pub enum AssertKind<O> { pub enum AssertKind<O> {

View file

@ -1,6 +1,6 @@
use smallvec::SmallVec; use smallvec::SmallVec;
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind}; use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
use rustc_ast::InlineAsmTemplatePiece; use rustc_ast::InlineAsmTemplatePiece;
pub use rustc_ast::Mutability; pub use rustc_ast::Mutability;
use rustc_macros::HashStable; use rustc_macros::HashStable;
@ -118,11 +118,11 @@ impl<'tcx> Terminator<'tcx> {
self.kind.successors_mut() self.kind.successors_mut()
} }
pub fn unwind(&self) -> Option<&Option<BasicBlock>> { pub fn unwind(&self) -> Option<&UnwindAction> {
self.kind.unwind() self.kind.unwind()
} }
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
self.kind.unwind_mut() self.kind.unwind_mut()
} }
} }
@ -135,34 +135,34 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn successors(&self) -> Successors<'_> { pub fn successors(&self) -> Successors<'_> {
use self::TerminatorKind::*; use self::TerminatorKind::*;
match *self { match *self {
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
| Yield { resume: t, drop: Some(ref u), .. }
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
| FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) }
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
}
Goto { target: t }
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
| Call { target: Some(t), unwind: _, .. }
| Yield { resume: t, drop: None, .. }
| Drop { target: t, unwind: _, .. }
| Assert { target: t, unwind: _, .. }
| FalseUnwind { real_target: t, unwind: _ }
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
| InlineAsm { destination: Some(t), unwind: _, .. } => {
Some(t).into_iter().chain((&[]).into_iter().copied())
}
Resume Resume
| Abort | Abort
| GeneratorDrop | GeneratorDrop
| Return | Return
| Unreachable | Unreachable
| Call { target: None, cleanup: None, .. } | Call { target: None, unwind: _, .. }
| InlineAsm { destination: None, cleanup: None, .. } => { | InlineAsm { destination: None, unwind: _, .. } => {
None.into_iter().chain((&[]).into_iter().copied()) None.into_iter().chain((&[]).into_iter().copied())
} }
Goto { target: t }
| Call { target: None, cleanup: Some(t), .. }
| Call { target: Some(t), cleanup: None, .. }
| Yield { resume: t, drop: None, .. }
| Drop { target: t, unwind: None, .. }
| Assert { target: t, cleanup: None, .. }
| FalseUnwind { real_target: t, unwind: None }
| InlineAsm { destination: Some(t), cleanup: None, .. }
| InlineAsm { destination: None, cleanup: Some(t), .. } => {
Some(t).into_iter().chain((&[]).into_iter().copied())
}
Call { target: Some(t), cleanup: Some(ref u), .. }
| Yield { resume: t, drop: Some(ref u), .. }
| Drop { target: t, unwind: Some(ref u), .. }
| Assert { target: t, cleanup: Some(ref u), .. }
| FalseUnwind { real_target: t, unwind: Some(ref u) }
| InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
}
SwitchInt { ref targets, .. } => { SwitchInt { ref targets, .. } => {
None.into_iter().chain(targets.targets.iter().copied()) None.into_iter().chain(targets.targets.iter().copied())
} }
@ -175,32 +175,34 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
use self::TerminatorKind::*; use self::TerminatorKind::*;
match *self { match *self {
Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) }
| InlineAsm {
destination: Some(ref mut t),
unwind: UnwindAction::Cleanup(ref mut u),
..
} => Some(t).into_iter().chain(slice::from_mut(u)),
Goto { target: ref mut t }
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
| Call { target: Some(ref mut t), unwind: _, .. }
| Yield { resume: ref mut t, drop: None, .. }
| Drop { target: ref mut t, unwind: _, .. }
| Assert { target: ref mut t, unwind: _, .. }
| FalseUnwind { real_target: ref mut t, unwind: _ }
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
| InlineAsm { destination: Some(ref mut t), unwind: _, .. } => {
Some(t).into_iter().chain(&mut [])
}
Resume Resume
| Abort | Abort
| GeneratorDrop | GeneratorDrop
| Return | Return
| Unreachable | Unreachable
| Call { target: None, cleanup: None, .. } | Call { target: None, unwind: _, .. }
| InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), | InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []),
Goto { target: ref mut t }
| Call { target: None, cleanup: Some(ref mut t), .. }
| Call { target: Some(ref mut t), cleanup: None, .. }
| Yield { resume: ref mut t, drop: None, .. }
| Drop { target: ref mut t, unwind: None, .. }
| Assert { target: ref mut t, cleanup: None, .. }
| FalseUnwind { real_target: ref mut t, unwind: None }
| InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
| InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
Some(t).into_iter().chain(&mut [])
}
Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
| FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
| InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
Some(t).into_iter().chain(slice::from_mut(u))
}
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets), SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
FalseEdge { ref mut real_target, ref mut imaginary_target } => { FalseEdge { ref mut real_target, ref mut imaginary_target } => {
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
@ -208,7 +210,7 @@ impl<'tcx> TerminatorKind<'tcx> {
} }
} }
pub fn unwind(&self) -> Option<&Option<BasicBlock>> { pub fn unwind(&self) -> Option<&UnwindAction> {
match *self { match *self {
TerminatorKind::Goto { .. } TerminatorKind::Goto { .. }
| TerminatorKind::Resume | TerminatorKind::Resume
@ -219,15 +221,15 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::Yield { .. } | TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. } | TerminatorKind::SwitchInt { .. }
| TerminatorKind::FalseEdge { .. } => None, | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref unwind, .. } TerminatorKind::Call { ref unwind, .. }
| TerminatorKind::Assert { cleanup: ref unwind, .. } | TerminatorKind::Assert { ref unwind, .. }
| TerminatorKind::Drop { ref unwind, .. } | TerminatorKind::Drop { ref unwind, .. }
| TerminatorKind::FalseUnwind { ref unwind, .. } | TerminatorKind::FalseUnwind { ref unwind, .. }
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind), | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
} }
} }
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
match *self { match *self {
TerminatorKind::Goto { .. } TerminatorKind::Goto { .. }
| TerminatorKind::Resume | TerminatorKind::Resume
@ -238,11 +240,11 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::Yield { .. } | TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. } | TerminatorKind::SwitchInt { .. }
| TerminatorKind::FalseEdge { .. } => None, | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref mut unwind, .. } TerminatorKind::Call { ref mut unwind, .. }
| TerminatorKind::Assert { cleanup: ref mut unwind, .. } | TerminatorKind::Assert { ref mut unwind, .. }
| TerminatorKind::Drop { ref mut unwind, .. } | TerminatorKind::Drop { ref mut unwind, .. }
| TerminatorKind::FalseUnwind { ref mut unwind, .. } | TerminatorKind::FalseUnwind { ref mut unwind, .. }
| TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind), | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
} }
} }
@ -386,31 +388,33 @@ impl<'tcx> TerminatorKind<'tcx> {
.map(|&u| Cow::Owned(u.to_string())) .map(|&u| Cow::Owned(u.to_string()))
.chain(iter::once("otherwise".into())) .chain(iter::once("otherwise".into()))
.collect(), .collect(),
Call { target: Some(_), cleanup: Some(_), .. } => { Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
vec!["return".into(), "unwind".into()] vec!["return".into(), "unwind".into()]
} }
Call { target: Some(_), cleanup: None, .. } => vec!["return".into()], Call { target: Some(_), unwind: UnwindAction::Continue, .. } => vec!["return".into()],
Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()], Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
Call { target: None, cleanup: None, .. } => vec![], Call { target: None, unwind: UnwindAction::Continue, .. } => vec![],
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
Yield { drop: None, .. } => vec!["resume".into()], Yield { drop: None, .. } => vec!["resume".into()],
Drop { unwind: None, .. } => { Drop { unwind: UnwindAction::Continue, .. } => vec!["return".into()],
vec!["return".into()] Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
} Assert { unwind: UnwindAction::Continue, .. } => vec!["".into()],
Drop { unwind: Some(_), .. } => {
vec!["return".into(), "unwind".into()]
}
Assert { cleanup: None, .. } => vec!["".into()],
Assert { .. } => vec!["success".into(), "unwind".into()], Assert { .. } => vec!["success".into(), "unwind".into()],
FalseEdge { .. } => vec!["real".into(), "imaginary".into()], FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => {
FalseUnwind { unwind: None, .. } => vec!["real".into()], vec!["real".into(), "cleanup".into()]
InlineAsm { destination: Some(_), cleanup: Some(_), .. } => { }
FalseUnwind { unwind: UnwindAction::Continue, .. } => vec!["real".into()],
InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
vec!["return".into(), "unwind".into()] vec!["return".into(), "unwind".into()]
} }
InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()], InlineAsm { destination: Some(_), unwind: UnwindAction::Continue, .. } => {
InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], vec!["return".into()]
InlineAsm { destination: None, cleanup: None, .. } => vec![], }
InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
vec!["unwind".into()]
}
InlineAsm { destination: None, unwind: UnwindAction::Continue, .. } => vec![],
} }
} }
} }

View file

@ -509,7 +509,7 @@ macro_rules! make_mir_visitor {
args, args,
destination, destination,
target: _, target: _,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _ fn_span: _
} => { } => {
@ -529,7 +529,7 @@ macro_rules! make_mir_visitor {
expected: _, expected: _,
msg, msg,
target: _, target: _,
cleanup: _, unwind: _,
} => { } => {
self.visit_operand(cond, location); self.visit_operand(cond, location);
self.visit_assert_message(msg, location); self.visit_assert_message(msg, location);
@ -555,7 +555,7 @@ macro_rules! make_mir_visitor {
options: _, options: _,
line_spans: _, line_spans: _,
destination: _, destination: _,
cleanup: _, unwind: _,
} => { } => {
for op in operands { for op in operands {
match op { match op {

View file

@ -171,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![Operand::Move(size), Operand::Move(align)], args: vec![Operand::Move(size), Operand::Move(align)],
destination: storage, destination: storage,
target: Some(success), target: Some(success),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: expr_span, fn_span: expr_span,
}, },
@ -702,7 +702,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.terminate( this.cfg.terminate(
block, block,
outer_source_info, outer_source_info,
TerminatorKind::Drop { place: to_drop, target: success, unwind: None }, TerminatorKind::Drop {
place: to_drop,
target: success,
unwind: UnwindAction::Continue,
},
); );
this.diverge_from(block); this.diverge_from(block);
block = success; block = success;

View file

@ -228,7 +228,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.terminate( this.cfg.terminate(
loop_block, loop_block,
source_info, source_info,
TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, TerminatorKind::FalseUnwind {
real_target: body_block,
unwind: UnwindAction::Continue,
},
); );
this.diverge_from(loop_block); this.diverge_from(loop_block);
@ -264,7 +267,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Call { TerminatorKind::Call {
func: fun, func: fun,
args, args,
cleanup: None, unwind: UnwindAction::Continue,
destination, destination,
// The presence or absence of a return edge affects control-flow sensitive // The presence or absence of a return edge affects control-flow sensitive
// MIR checks and ultimately whether code is accepted or not. We can only // MIR checks and ultimately whether code is accepted or not. We can only
@ -466,7 +469,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else { } else {
Some(destination_block) Some(destination_block)
}, },
cleanup: None, unwind: UnwindAction::Continue,
}, },
); );
if options.contains(InlineAsmOptions::MAY_UNWIND) { if options.contains(InlineAsmOptions::MAY_UNWIND) {

View file

@ -263,7 +263,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![Operand::Move(ref_string)], args: vec![Operand::Move(ref_string)],
destination: ref_str, destination: ref_str,
target: Some(eq_block), target: Some(eq_block),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: source_info.span fn_span: source_info.span
} }
@ -466,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![val, expect], args: vec![val, expect],
destination: eq_result, destination: eq_result,
target: Some(eq_block), target: Some(eq_block),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: source_info.span, fn_span: source_info.span,
}, },

View file

@ -369,7 +369,7 @@ impl DropTree {
let terminator = TerminatorKind::Drop { let terminator = TerminatorKind::Drop {
target: blocks[drop_data.1].unwrap(), target: blocks[drop_data.1].unwrap(),
// The caller will handle this if needed. // The caller will handle this if needed.
unwind: None, unwind: UnwindAction::Continue,
place: drop_data.0.local.into(), place: drop_data.0.local.into(),
}; };
cfg.terminate(block, drop_data.0.source_info, terminator); cfg.terminate(block, drop_data.0.source_info, terminator);
@ -1141,7 +1141,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.terminate( self.cfg.terminate(
block, block,
source_info, source_info,
TerminatorKind::Drop { place, target: assign, unwind: Some(assign_unwind) }, TerminatorKind::Drop {
place,
target: assign,
unwind: UnwindAction::Cleanup(assign_unwind),
},
); );
self.diverge_from(block); self.diverge_from(block);
@ -1165,7 +1169,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.terminate( self.cfg.terminate(
block, block,
source_info, source_info,
TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None }, TerminatorKind::Assert {
cond,
expected,
msg,
target: success_block,
unwind: UnwindAction::Continue,
},
); );
self.diverge_from(block); self.diverge_from(block);
@ -1244,7 +1254,11 @@ fn build_scope_drops<'tcx>(
cfg.terminate( cfg.terminate(
block, block,
source_info, source_info,
TerminatorKind::Drop { place: local.into(), target: next, unwind: None }, TerminatorKind::Drop {
place: local.into(),
target: next,
unwind: UnwindAction::Continue,
},
); );
block = next; block = next;
} }
@ -1432,10 +1446,10 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
} }
} }
TerminatorKind::FalseUnwind { unwind, .. } TerminatorKind::FalseUnwind { unwind, .. }
| TerminatorKind::Call { cleanup: unwind, .. } | TerminatorKind::Call { unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. } | TerminatorKind::Assert { unwind, .. }
| TerminatorKind::InlineAsm { cleanup: unwind, .. } => { | TerminatorKind::InlineAsm { unwind, .. } => {
*unwind = Some(to); *unwind = UnwindAction::Cleanup(to);
} }
TerminatorKind::Goto { .. } TerminatorKind::Goto { .. }
| TerminatorKind::SwitchInt { .. } | TerminatorKind::SwitchInt { .. }

View file

@ -3,7 +3,7 @@ use rustc_data_structures::graph::iterate::{
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
}; };
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
@ -149,7 +149,9 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
let terminator = self.body[bb].terminator(); let terminator = self.body[bb].terminator();
if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 { if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
&& terminator.successors().count() > 1
{
return true; return true;
} }
// Don't traverse successors of recursive calls or false CFG edges. // Don't traverse successors of recursive calls or false CFG edges.

View file

@ -77,10 +77,10 @@ impl Unwind {
} }
} }
fn into_option(self) -> Option<BasicBlock> { fn into_action(self) -> UnwindAction {
match self { match self {
Unwind::To(bb) => Some(bb), Unwind::To(bb) => UnwindAction::Cleanup(bb),
Unwind::InCleanup => None, Unwind::InCleanup => UnwindAction::Continue,
} }
} }
@ -236,7 +236,7 @@ where
TerminatorKind::Drop { TerminatorKind::Drop {
place: self.place, place: self.place,
target: self.succ, target: self.succ,
unwind: self.unwind.into_option(), unwind: self.unwind.into_action(),
}, },
); );
} }
@ -640,7 +640,7 @@ where
args: vec![Operand::Move(Place::from(ref_place))], args: vec![Operand::Move(Place::from(ref_place))],
destination: unit_temp, destination: unit_temp,
target: Some(succ), target: Some(succ),
cleanup: unwind.into_option(), unwind: unwind.into_action(),
from_hir_call: true, from_hir_call: true,
fn_span: self.source_info.span, fn_span: self.source_info.span,
}, },
@ -717,7 +717,7 @@ where
TerminatorKind::Drop { TerminatorKind::Drop {
place: tcx.mk_place_deref(ptr), place: tcx.mk_place_deref(ptr),
target: loop_block, target: loop_block,
unwind: unwind.into_option(), unwind: unwind.into_action(),
}, },
); );
@ -946,7 +946,7 @@ where
args, args,
destination: unit_temp, destination: unit_temp,
target: Some(target), target: Some(target),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: self.source_info.span, fn_span: self.source_info.span,
}; // FIXME(#43234) }; // FIXME(#43234)
@ -959,7 +959,7 @@ where
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let block = let block =
TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() }; TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() };
self.new_block(unwind, block) self.new_block(unwind, block)
} }

View file

@ -1,4 +1,4 @@
use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets, UnwindAction};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
@ -478,10 +478,10 @@ impl Direction for Forward {
Goto { target } => propagate(target, exit_state), Goto { target } => propagate(target, exit_state),
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } Assert { target, unwind, expected: _, msg: _, cond: _ }
| Drop { target, unwind, place: _ } | Drop { target, unwind, place: _ }
| FalseUnwind { real_target: target, unwind } => { | FalseUnwind { real_target: target, unwind } => {
if let Some(unwind) = unwind { if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state); propagate(unwind, exit_state);
} }
@ -503,7 +503,7 @@ impl Direction for Forward {
} }
Call { Call {
cleanup, unwind,
destination, destination,
target, target,
func: _, func: _,
@ -511,7 +511,7 @@ impl Direction for Forward {
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {
if let Some(unwind) = cleanup { if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state); propagate(unwind, exit_state);
} }
@ -533,9 +533,9 @@ impl Direction for Forward {
options: _, options: _,
line_spans: _, line_spans: _,
destination, destination,
cleanup, unwind,
} => { } => {
if let Some(unwind) = cleanup { if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state); propagate(unwind, exit_state);
} }

View file

@ -39,7 +39,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
args: vec![], args: vec![],
destination: dummy_place.clone(), destination: dummy_place.clone(),
target: Some(mir::START_BLOCK), target: Some(mir::START_BLOCK),
cleanup: None, unwind: mir::UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: DUMMY_SP, fn_span: DUMMY_SP,
}, },
@ -53,7 +53,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
args: vec![], args: vec![],
destination: dummy_place.clone(), destination: dummy_place.clone(),
target: Some(mir::START_BLOCK), target: Some(mir::START_BLOCK),
cleanup: None, unwind: mir::UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: DUMMY_SP, fn_span: DUMMY_SP,
}, },

View file

@ -398,7 +398,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
ref args, ref args,
destination, destination,
target, target,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {
@ -417,7 +417,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
options: _, options: _,
line_spans: _, line_spans: _,
destination: _, destination: _,
cleanup: _, unwind: _,
} => { } => {
for op in operands { for op in operands {
match *op { match *op {

View file

@ -125,13 +125,13 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
for bb in calls_to_terminate { for bb in calls_to_terminate {
let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap(); let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
*cleanup = Some(abort_bb); *cleanup = UnwindAction::Cleanup(abort_bb);
} }
} }
for id in cleanups_to_remove { for id in cleanups_to_remove {
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
*cleanup = None; *cleanup = UnwindAction::Continue;
} }
// We may have invalidated some `cleanup` blocks so clean those up now. // We may have invalidated some `cleanup` blocks so clean those up now.

View file

@ -50,10 +50,10 @@ impl AddCallGuards {
for block in body.basic_blocks_mut() { for block in body.basic_blocks_mut() {
match block.terminator { match block.terminator {
Some(Terminator { Some(Terminator {
kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. }, kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
source_info, source_info,
}) if pred_count[*destination] > 1 }) if pred_count[*destination] > 1
&& (cleanup.is_some() || self == &AllCallEdges) => && (matches!(unwind, UnwindAction::Cleanup(_)) || self == &AllCallEdges) =>
{ {
// It's a critical edge, break it // It's a critical edge, break it
let call_guard = BasicBlockData { let call_guard = BasicBlockData {

View file

@ -228,7 +228,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
fn assert_panic( fn assert_panic(
_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ecx: &mut InterpCx<'mir, 'tcx, Self>,
_msg: &rustc_middle::mir::AssertMessage<'tcx>, _msg: &rustc_middle::mir::AssertMessage<'tcx>,
_unwind: Option<rustc_middle::mir::BasicBlock>, _unwind: rustc_middle::mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
bug!("panics terminators are not evaluated in ConstProp") bug!("panics terminators are not evaluated in ConstProp")
} }

View file

@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> {
args: vec![], args: vec![],
destination: self.dummy_place.clone(), destination: self.dummy_place.clone(),
target: Some(TEMP_BLOCK), target: Some(TEMP_BLOCK),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: false, from_hir_call: false,
fn_span: DUMMY_SP, fn_span: DUMMY_SP,
}, },

View file

@ -120,7 +120,7 @@ fn remove_dead_unwinds<'tcx>(
.into_results_cursor(body); .into_results_cursor(body);
for (bb, bb_data) in body.basic_blocks.iter_enumerated() { for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
let place = match bb_data.terminator().kind { let place = match bb_data.terminator().kind {
TerminatorKind::Drop { ref place, unwind: Some(_), .. } => { TerminatorKind::Drop { ref place, unwind: UnwindAction::Cleanup(_), .. } => {
und.derefer(place.as_ref(), body).unwrap_or(*place) und.derefer(place.as_ref(), body).unwrap_or(*place)
} }
_ => continue, _ => continue,
@ -417,7 +417,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
if data.is_cleanup { if data.is_cleanup {
Unwind::InCleanup Unwind::InCleanup
} else { } else {
Unwind::To(Option::unwrap_or(unwind, resume_block)) match unwind {
UnwindAction::Cleanup(cleanup) => Unwind::To(cleanup),
UnwindAction::Continue => Unwind::To(resume_block),
}
}, },
bb, bb,
), ),
@ -474,7 +477,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
continue; continue;
} }
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination, target: Some(tgt), cleanup: Some(_), .. destination,
target: Some(tgt),
unwind: UnwindAction::Cleanup(_),
..
} = data.terminator().kind } = data.terminator().kind
{ {
assert!(!self.patch.is_patched(bb)); assert!(!self.patch.is_patched(bb));
@ -543,8 +549,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
// There may be a critical edge after this call, // There may be a critical edge after this call,
// so mark the return as initialized *before* the // so mark the return as initialized *before* the
// call. // call.
if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } = if let TerminatorKind::Call {
data.terminator().kind destination,
target: Some(_),
unwind: UnwindAction::Continue,
..
} = data.terminator().kind
{ {
assert!(!self.patch.is_patched(bb)); assert!(!self.patch.is_patched(bb));

View file

@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
args, args,
destination: _, destination: _,
target: _, target: _,
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} = &terminator.kind } = &terminator.kind

View file

@ -1060,7 +1060,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let unwind = if block_data.is_cleanup { let unwind = if block_data.is_cleanup {
Unwind::InCleanup Unwind::InCleanup
} else { } else {
Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block())) Unwind::To(match *unwind {
UnwindAction::Cleanup(tgt) => tgt,
UnwindAction::Continue => elaborator.patch.resume_block(),
})
}; };
elaborate_drop( elaborate_drop(
&mut elaborator, &mut elaborator,
@ -1147,7 +1150,7 @@ fn insert_panic_block<'tcx>(
expected: true, expected: true,
msg: message, msg: message,
target: assert_block, target: assert_block,
cleanup: None, unwind: UnwindAction::Continue,
}; };
let source_info = SourceInfo::outermost(body.span); let source_info = SourceInfo::outermost(body.span);
@ -1248,8 +1251,8 @@ fn create_generator_resume_function<'tcx>(
} else if !block.is_cleanup { } else if !block.is_cleanup {
// Any terminators that *can* unwind but don't have an unwind target set are also // Any terminators that *can* unwind but don't have an unwind target set are also
// pointed at our poisoning block (unless they're part of the cleanup path). // pointed at our poisoning block (unless they're part of the cleanup path).
if let Some(unwind @ None) = block.terminator_mut().unwind_mut() { if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
*unwind = Some(poison_block); *unwind = UnwindAction::Cleanup(poison_block);
} }
} }
} }
@ -1294,8 +1297,11 @@ fn create_generator_resume_function<'tcx>(
fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
let return_block = insert_term_block(body, TerminatorKind::Return); let return_block = insert_term_block(body, TerminatorKind::Return);
let term = let term = TerminatorKind::Drop {
TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None }; place: Place::from(SELF_ARG),
target: return_block,
unwind: UnwindAction::Continue,
};
let source_info = SourceInfo::outermost(body.span); let source_info = SourceInfo::outermost(body.span);
// Create a block to destroy an unresumed generators. This can only destroy upvars. // Create a block to destroy an unresumed generators. This can only destroy upvars.
@ -1670,7 +1676,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
args, args,
destination, destination,
target: Some(_), target: Some(_),
cleanup: _, unwind: _,
from_hir_call: _, from_hir_call: _,
fn_span: _, fn_span: _,
} => { } => {

View file

@ -453,7 +453,7 @@ impl<'tcx> Inliner<'tcx> {
// If the place doesn't actually need dropping, treat it like a regular goto. // If the place doesn't actually need dropping, treat it like a regular goto.
let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind { if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
work_list.push(unwind); work_list.push(unwind);
} }
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
@ -500,7 +500,7 @@ impl<'tcx> Inliner<'tcx> {
) { ) {
let terminator = caller_body[callsite.block].terminator.take().unwrap(); let terminator = caller_body[callsite.block].terminator.take().unwrap();
match terminator.kind { match terminator.kind {
TerminatorKind::Call { args, destination, cleanup, .. } => { TerminatorKind::Call { args, destination, unwind, .. } => {
// If the call is something like `a[*i] = f(i)`, where // If the call is something like `a[*i] = f(i)`, where
// `i : &mut usize`, then just duplicating the `a[*i]` // `i : &mut usize`, then just duplicating the `a[*i]`
// Place could result in two different locations if `f` // Place could result in two different locations if `f`
@ -571,7 +571,7 @@ impl<'tcx> Inliner<'tcx> {
destination: destination_local, destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite, callsite,
cleanup_block: cleanup, cleanup_block: unwind,
in_cleanup_block: false, in_cleanup_block: false,
tcx: self.tcx, tcx: self.tcx,
expn_data, expn_data,
@ -813,14 +813,14 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty); let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
if ty.needs_drop(tcx, self.param_env) { if ty.needs_drop(tcx, self.param_env) {
self.cost += CALL_PENALTY; self.cost += CALL_PENALTY;
if unwind.is_some() { if let UnwindAction::Cleanup(_) = unwind {
self.cost += LANDINGPAD_PENALTY; self.cost += LANDINGPAD_PENALTY;
} }
} else { } else {
self.cost += INSTR_COST; self.cost += INSTR_COST;
} }
} }
TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty()); let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty());
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
// Don't give intrinsics the extra penalty for calls // Don't give intrinsics the extra penalty for calls
@ -828,20 +828,20 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
} else { } else {
CALL_PENALTY CALL_PENALTY
}; };
if cleanup.is_some() { if let UnwindAction::Cleanup(_) = unwind {
self.cost += LANDINGPAD_PENALTY; self.cost += LANDINGPAD_PENALTY;
} }
} }
TerminatorKind::Assert { cleanup, .. } => { TerminatorKind::Assert { unwind, .. } => {
self.cost += CALL_PENALTY; self.cost += CALL_PENALTY;
if cleanup.is_some() { if let UnwindAction::Cleanup(_) = unwind {
self.cost += LANDINGPAD_PENALTY; self.cost += LANDINGPAD_PENALTY;
} }
} }
TerminatorKind::Resume => self.cost += RESUME_PENALTY, TerminatorKind::Resume => self.cost += RESUME_PENALTY,
TerminatorKind::InlineAsm { cleanup, .. } => { TerminatorKind::InlineAsm { unwind, .. } => {
self.cost += INSTR_COST; self.cost += INSTR_COST;
if cleanup.is_some() { if let UnwindAction::Cleanup(_) = unwind {
self.cost += LANDINGPAD_PENALTY; self.cost += LANDINGPAD_PENALTY;
} }
} }
@ -979,7 +979,7 @@ struct Integrator<'a, 'tcx> {
destination: Local, destination: Local,
callsite_scope: SourceScopeData<'tcx>, callsite_scope: SourceScopeData<'tcx>,
callsite: &'a CallSite<'tcx>, callsite: &'a CallSite<'tcx>,
cleanup_block: Option<BasicBlock>, cleanup_block: UnwindAction,
in_cleanup_block: bool, in_cleanup_block: bool,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
expn_data: LocalExpnId, expn_data: LocalExpnId,
@ -1014,18 +1014,20 @@ impl Integrator<'_, '_> {
new new
} }
fn map_unwind(&self, unwind: Option<BasicBlock>) -> Option<BasicBlock> { fn map_unwind(&self, unwind: UnwindAction) -> UnwindAction {
if self.in_cleanup_block { if self.in_cleanup_block {
if unwind.is_some() { match unwind {
bug!("cleanup on cleanup block"); UnwindAction::Cleanup(_) => {
bug!("cleanup on cleanup block");
}
UnwindAction::Continue => return unwind,
} }
return unwind;
} }
match unwind { match unwind {
Some(target) => Some(self.map_block(target)), UnwindAction::Cleanup(target) => UnwindAction::Cleanup(self.map_block(target)),
// Add an unwind edge to the original call's cleanup block // Add an unwind edge to the original call's cleanup block
None => self.cleanup_block, UnwindAction::Continue => self.cleanup_block,
} }
} }
} }
@ -1116,15 +1118,15 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
*target = self.map_block(*target); *target = self.map_block(*target);
*unwind = self.map_unwind(*unwind); *unwind = self.map_unwind(*unwind);
} }
TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => { TerminatorKind::Call { ref mut target, ref mut unwind, .. } => {
if let Some(ref mut tgt) = *target { if let Some(ref mut tgt) = *target {
*tgt = self.map_block(*tgt); *tgt = self.map_block(*tgt);
} }
*cleanup = self.map_unwind(*cleanup); *unwind = self.map_unwind(*unwind);
} }
TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { TerminatorKind::Assert { ref mut target, ref mut unwind, .. } => {
*target = self.map_block(*target); *target = self.map_block(*target);
*cleanup = self.map_unwind(*cleanup); *unwind = self.map_unwind(*unwind);
} }
TerminatorKind::Return => { TerminatorKind::Return => {
terminator.kind = if let Some(tgt) = self.callsite.target { terminator.kind = if let Some(tgt) = self.callsite.target {
@ -1133,11 +1135,12 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
TerminatorKind::Unreachable TerminatorKind::Unreachable
} }
} }
TerminatorKind::Resume => { TerminatorKind::Resume => match self.cleanup_block {
if let Some(tgt) = self.cleanup_block { UnwindAction::Cleanup(tgt) => {
terminator.kind = TerminatorKind::Goto { target: tgt } terminator.kind = TerminatorKind::Goto { target: tgt };
} }
} UnwindAction::Continue => (),
},
TerminatorKind::Abort => {} TerminatorKind::Abort => {}
TerminatorKind::Unreachable => {} TerminatorKind::Unreachable => {}
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => { TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
@ -1149,11 +1152,11 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
{ {
bug!("False unwinds should have been removed before inlining") bug!("False unwinds should have been removed before inlining")
} }
TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => { TerminatorKind::InlineAsm { ref mut destination, ref mut unwind, .. } => {
if let Some(ref mut tgt) = *destination { if let Some(ref mut tgt) = *destination {
*tgt = self.map_block(*tgt); *tgt = self.map_block(*tgt);
} }
*cleanup = self.map_unwind(*cleanup); *unwind = self.map_unwind(*unwind);
} }
} }
} }

View file

@ -159,7 +159,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
ref mut args, ref mut args,
destination, destination,
target, target,
cleanup, unwind,
fn_span, fn_span,
.. ..
} if let ty::FnDef(def_id, _) = *literal.ty().kind() } if let ty::FnDef(def_id, _) = *literal.ty().kind()
@ -196,7 +196,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
}; };
method(place) method(place)
}).collect(); }).collect();
terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span }; terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span };
} }
_ => {} _ => {}
} }

View file

@ -54,7 +54,7 @@ fn lower_slice_len_call<'tcx>(
args, args,
destination, destination,
target: Some(bb), target: Some(bb),
cleanup: None, unwind: UnwindAction::Continue,
from_hir_call: true, from_hir_call: true,
.. ..
} => { } => {

View file

@ -103,11 +103,11 @@ impl RemoveNoopLandingPads {
for bb in postorder { for bb in postorder {
debug!(" processing {:?}", bb); debug!(" processing {:?}", bb);
if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
if let Some(unwind_bb) = *unwind { if let UnwindAction::Cleanup(unwind_bb) = *unwind {
if nop_landing_pads.contains(unwind_bb) { if nop_landing_pads.contains(unwind_bb) {
debug!(" removing noop landing pad"); debug!(" removing noop landing pad");
landing_pads_removed += 1; landing_pads_removed += 1;
*unwind = None; *unwind = UnwindAction::Continue;
} }
} }
} }

View file

@ -499,7 +499,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
args: vec![Operand::Move(ref_loc)], args: vec![Operand::Move(ref_loc)],
destination: dest, destination: dest,
target: Some(next), target: Some(next),
cleanup: Some(cleanup), unwind: UnwindAction::Cleanup(cleanup),
from_hir_call: true, from_hir_call: true,
fn_span: self.span, fn_span: self.span,
}, },
@ -540,7 +540,11 @@ impl<'tcx> CloneShimBuilder<'tcx> {
self.make_clone_call(dest_field, src_field, ity, next_block, unwind); self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
self.block( self.block(
vec![], vec![],
TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None }, TerminatorKind::Drop {
place: dest_field,
target: unwind,
unwind: UnwindAction::Continue,
},
true, true,
); );
unwind = next_unwind; unwind = next_unwind;
@ -776,10 +780,10 @@ fn build_call_shim<'tcx>(
args, args,
destination: Place::return_place(), destination: Place::return_place(),
target: Some(BasicBlock::new(1)), target: Some(BasicBlock::new(1)),
cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment { unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
Some(BasicBlock::new(3)) UnwindAction::Cleanup(BasicBlock::new(3))
} else { } else {
None UnwindAction::Continue
}, },
from_hir_call: true, from_hir_call: true,
fn_span: span, fn_span: span,
@ -792,7 +796,11 @@ fn build_call_shim<'tcx>(
block( block(
&mut blocks, &mut blocks,
vec![], vec![],
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }, TerminatorKind::Drop {
place: rcvr_place(),
target: BasicBlock::new(2),
unwind: UnwindAction::Continue,
},
false, false,
); );
} }
@ -803,7 +811,11 @@ fn build_call_shim<'tcx>(
block( block(
&mut blocks, &mut blocks,
vec![], vec![],
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }, TerminatorKind::Drop {
place: rcvr_place(),
target: BasicBlock::new(4),
unwind: UnwindAction::Continue,
},
true, true,
); );

View file

@ -318,7 +318,7 @@ fn check_terminator<'tcx>(
from_hir_call: _, from_hir_call: _,
destination: _, destination: _,
target: _, target: _,
cleanup: _, unwind: _,
fn_span: _, fn_span: _,
} => { } => {
let fn_ty = func.ty(body, tcx); let fn_ty = func.ty(body, tcx);
@ -361,7 +361,7 @@ fn check_terminator<'tcx>(
expected: _, expected: _,
msg: _, msg: _,
target: _, target: _,
cleanup: _, unwind: _,
} => check_operand(tcx, cond, span, body), } => check_operand(tcx, cond, span, body),
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),

View file

@ -868,7 +868,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
fn assert_panic( fn assert_panic(
ecx: &mut MiriInterpCx<'mir, 'tcx>, ecx: &mut MiriInterpCx<'mir, 'tcx>,
msg: &mir::AssertMessage<'tcx>, msg: &mir::AssertMessage<'tcx>,
unwind: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
ecx.assert_panic(msg, unwind) ecx.assert_panic(msg, unwind)
} }

View file

@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn assert_panic( fn assert_panic(
&mut self, &mut self,
msg: &mir::AssertMessage<'tcx>, msg: &mir::AssertMessage<'tcx>,
unwind: Option<mir::BasicBlock>, unwind: mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
use rustc_middle::mir::AssertKind::*; use rustc_middle::mir::AssertKind::*;
let this = self.eval_context_mut(); let this = self.eval_context_mut();