Auto merge of #102906 - nbdd0121:mir, r=wesleywiser,tmiasko
Refactor unwind in MIR This makes unwinding from current `Option<BasicBlock>` into ```rust enum UnwindAction { Continue, Cleanup(BasicBlock), Unreachable, Terminate, } ``` cc `@JakobDegen` `@RalfJung` `@Amanieu`
This commit is contained in:
commit
da14081468
294 changed files with 1225 additions and 933 deletions
|
@ -34,11 +34,6 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
|||
return;
|
||||
}
|
||||
|
||||
// This pass only runs on functions which themselves cannot unwind,
|
||||
// forcibly changing the body of the function to structurally provide
|
||||
// this guarantee by aborting on an unwind. If this function can unwind,
|
||||
// then there's nothing to do because it already should work correctly.
|
||||
//
|
||||
// Here we test for this function itself whether its ABI allows
|
||||
// unwinding or not.
|
||||
let body_ty = tcx.type_of(def_id).skip_binder();
|
||||
|
@ -107,31 +102,14 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
|||
}
|
||||
}
|
||||
|
||||
// For call instructions which need to be terminated, we insert a
|
||||
// singular basic block which simply terminates, and then configure the
|
||||
// `cleanup` attribute for all calls we found to this basic block we
|
||||
// insert which means that any unwinding that happens in the functions
|
||||
// will force an abort of the process.
|
||||
if !calls_to_terminate.is_empty() {
|
||||
let bb = BasicBlockData {
|
||||
statements: Vec::new(),
|
||||
is_cleanup: true,
|
||||
terminator: Some(Terminator {
|
||||
source_info: SourceInfo::outermost(body.span),
|
||||
kind: TerminatorKind::Abort,
|
||||
}),
|
||||
};
|
||||
let abort_bb = body.basic_blocks_mut().push(bb);
|
||||
|
||||
for bb in calls_to_terminate {
|
||||
let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = Some(abort_bb);
|
||||
}
|
||||
for id in calls_to_terminate {
|
||||
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = UnwindAction::Terminate;
|
||||
}
|
||||
|
||||
for id in cleanups_to_remove {
|
||||
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = None;
|
||||
*cleanup = UnwindAction::Unreachable;
|
||||
}
|
||||
|
||||
// We may have invalidated some `cleanup` blocks so clean those up now.
|
||||
|
|
|
@ -50,10 +50,11 @@ impl AddCallGuards {
|
|||
for block in body.basic_blocks_mut() {
|
||||
match block.terminator {
|
||||
Some(Terminator {
|
||||
kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. },
|
||||
kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
|
||||
source_info,
|
||||
}) if pred_count[*destination] > 1
|
||||
&& (cleanup.is_some() || self == &AllCallEdges) =>
|
||||
&& (matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate)
|
||||
|| self == &AllCallEdges) =>
|
||||
{
|
||||
// It's a critical edge, break it
|
||||
let call_guard = BasicBlockData {
|
||||
|
|
|
@ -221,7 +221,7 @@ fn insert_alignment_check<'tcx>(
|
|||
required: Operand::Copy(alignment),
|
||||
found: Operand::Copy(addr),
|
||||
},
|
||||
cleanup: None,
|
||||
unwind: UnwindAction::Terminate,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
|||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::MirPass;
|
|||
use rustc_const_eval::interpret::{
|
||||
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
|
||||
ImmTy, Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer,
|
||||
Scalar, StackPopCleanup, StackPopUnwind,
|
||||
Scalar, StackPopCleanup,
|
||||
};
|
||||
|
||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||
|
@ -209,7 +209,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
|||
_args: &[OpTy<'tcx>],
|
||||
_destination: &PlaceTy<'tcx>,
|
||||
_target: Option<BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
_unwind: UnwindAction,
|
||||
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
|||
_args: &[OpTy<'tcx>],
|
||||
_destination: &PlaceTy<'tcx>,
|
||||
_target: Option<BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
_unwind: UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
|||
fn assert_panic(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
||||
_unwind: Option<rustc_middle::mir::BasicBlock>,
|
||||
_unwind: rustc_middle::mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
bug!("panics terminators are not evaluated in ConstProp")
|
||||
}
|
||||
|
@ -959,7 +959,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
// None of these have Operands to const-propagate.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
@ -686,7 +686,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
// None of these have Operands to const-propagate.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
@ -818,7 +818,7 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
|
|||
TerminatorKind::Goto { .. } => "Goto",
|
||||
TerminatorKind::SwitchInt { .. } => "SwitchInt",
|
||||
TerminatorKind::Resume => "Resume",
|
||||
TerminatorKind::Abort => "Abort",
|
||||
TerminatorKind::Terminate => "Terminate",
|
||||
TerminatorKind::Return => "Return",
|
||||
TerminatorKind::Unreachable => "Unreachable",
|
||||
TerminatorKind::Drop { .. } => "Drop",
|
||||
|
|
|
@ -122,7 +122,7 @@ impl CoverageGraph {
|
|||
|
||||
match term.kind {
|
||||
TerminatorKind::Return { .. }
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. } => {
|
||||
// The `bb` has more than one _outgoing_ edge, or exits the function. Save the
|
||||
|
@ -136,7 +136,7 @@ impl CoverageGraph {
|
|||
debug!(" because term.kind = {:?}", term.kind);
|
||||
// Note that this condition is based on `TerminatorKind`, even though it
|
||||
// theoretically boils down to `successors().len() != 1`; that is, either zero
|
||||
// (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but
|
||||
// (e.g., `Return`, `Terminate`) or multiple successors (e.g., `SwitchInt`), but
|
||||
// since the BCB CFG ignores things like unwind branches (which exist in the
|
||||
// `Terminator`s `successors()` list) checking the number of successors won't
|
||||
// work.
|
||||
|
|
|
@ -869,7 +869,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
|
|||
|
||||
// Retain spans from all other terminators
|
||||
TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
|
@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> {
|
|||
args: vec![],
|
||||
destination: self.dummy_place.clone(),
|
||||
target: Some(TEMP_BLOCK),
|
||||
cleanup: None,
|
||||
unwind: UnwindAction::Continue,
|
||||
from_hir_call: false,
|
||||
fn_span: DUMMY_SP,
|
||||
},
|
||||
|
|
|
@ -567,7 +567,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
|||
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
||||
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
||||
_target: Option<BasicBlock>,
|
||||
_unwind: rustc_const_eval::interpret::StackPopUnwind,
|
||||
_unwind: UnwindAction,
|
||||
) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -578,7 +578,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
|||
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
||||
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
||||
_target: Option<BasicBlock>,
|
||||
_unwind: rustc_const_eval::interpret::StackPopUnwind,
|
||||
_unwind: UnwindAction,
|
||||
) -> interpret::InterpResult<'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -586,7 +586,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
|||
fn assert_panic(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
||||
_unwind: Option<BasicBlock>,
|
||||
_unwind: UnwindAction,
|
||||
) -> interpret::InterpResult<'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
@ -645,8 +645,8 @@ impl WriteInfo {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume { .. }
|
||||
| TerminatorKind::Abort { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable { .. } => (),
|
||||
TerminatorKind::Drop { .. } => {
|
||||
|
|
|
@ -120,7 +120,7 @@ fn remove_dead_unwinds<'tcx>(
|
|||
.into_results_cursor(body);
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
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)
|
||||
}
|
||||
_ => continue,
|
||||
|
@ -160,7 +160,7 @@ fn remove_dead_unwinds<'tcx>(
|
|||
let basic_blocks = body.basic_blocks.as_mut();
|
||||
for &bb in dead_unwinds.iter() {
|
||||
if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() {
|
||||
*unwind = None;
|
||||
*unwind = UnwindAction::Unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +399,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
let loc = Location { block: bb, statement_index: data.statements.len() };
|
||||
let terminator = data.terminator();
|
||||
|
||||
let resume_block = self.patch.resume_block();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { mut place, target, unwind } => {
|
||||
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
|
||||
|
@ -408,19 +407,31 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
|
||||
self.init_data.seek_before(loc);
|
||||
match self.move_data().rev_lookup.find(place.as_ref()) {
|
||||
LookupResult::Exact(path) => elaborate_drop(
|
||||
&mut Elaborator { ctxt: self },
|
||||
terminator.source_info,
|
||||
place,
|
||||
path,
|
||||
target,
|
||||
if data.is_cleanup {
|
||||
LookupResult::Exact(path) => {
|
||||
let unwind = if data.is_cleanup {
|
||||
Unwind::InCleanup
|
||||
} else {
|
||||
Unwind::To(Option::unwrap_or(unwind, resume_block))
|
||||
},
|
||||
bb,
|
||||
),
|
||||
match unwind {
|
||||
UnwindAction::Cleanup(cleanup) => Unwind::To(cleanup),
|
||||
UnwindAction::Continue => Unwind::To(self.patch.resume_block()),
|
||||
UnwindAction::Unreachable => {
|
||||
Unwind::To(self.patch.unreachable_cleanup_block())
|
||||
}
|
||||
UnwindAction::Terminate => {
|
||||
Unwind::To(self.patch.terminate_block())
|
||||
}
|
||||
}
|
||||
};
|
||||
elaborate_drop(
|
||||
&mut Elaborator { ctxt: self },
|
||||
terminator.source_info,
|
||||
place,
|
||||
path,
|
||||
target,
|
||||
unwind,
|
||||
bb,
|
||||
)
|
||||
}
|
||||
LookupResult::Parent(..) => {
|
||||
if !matches!(
|
||||
terminator.source_info.span.desugaring_kind(),
|
||||
|
@ -474,7 +485,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
if let TerminatorKind::Call {
|
||||
destination, target: Some(tgt), cleanup: Some(_), ..
|
||||
destination,
|
||||
target: Some(tgt),
|
||||
unwind: UnwindAction::Cleanup(_),
|
||||
..
|
||||
} = data.terminator().kind
|
||||
{
|
||||
assert!(!self.patch.is_patched(bb));
|
||||
|
@ -543,8 +557,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
// There may be a critical edge after this call,
|
||||
// so mark the return as initialized *before* the
|
||||
// call.
|
||||
if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } =
|
||||
data.terminator().kind
|
||||
if let TerminatorKind::Call {
|
||||
destination,
|
||||
target: Some(_),
|
||||
unwind: UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate,
|
||||
..
|
||||
} = data.terminator().kind
|
||||
{
|
||||
assert!(!self.patch.is_patched(bb));
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
|
|||
args,
|
||||
destination: _,
|
||||
target: _,
|
||||
cleanup: _,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} = &terminator.kind
|
||||
|
|
|
@ -1060,7 +1060,12 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
let unwind = if block_data.is_cleanup {
|
||||
Unwind::InCleanup
|
||||
} 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(),
|
||||
UnwindAction::Unreachable => elaborator.patch.unreachable_cleanup_block(),
|
||||
UnwindAction::Terminate => elaborator.patch.terminate_block(),
|
||||
})
|
||||
};
|
||||
elaborate_drop(
|
||||
&mut elaborator,
|
||||
|
@ -1147,7 +1152,7 @@ fn insert_panic_block<'tcx>(
|
|||
expected: true,
|
||||
msg: message,
|
||||
target: assert_block,
|
||||
cleanup: None,
|
||||
unwind: UnwindAction::Continue,
|
||||
};
|
||||
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
|
@ -1189,7 +1194,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
|||
// These never unwind.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
@ -1248,8 +1253,8 @@ fn create_generator_resume_function<'tcx>(
|
|||
} else if !block.is_cleanup {
|
||||
// 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).
|
||||
if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
|
||||
*unwind = Some(poison_block);
|
||||
if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
|
||||
*unwind = UnwindAction::Cleanup(poison_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1294,8 +1299,11 @@ fn create_generator_resume_function<'tcx>(
|
|||
fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
|
||||
let return_block = insert_term_block(body, TerminatorKind::Return);
|
||||
|
||||
let term =
|
||||
TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
|
||||
let term = TerminatorKind::Drop {
|
||||
place: Place::from(SELF_ARG),
|
||||
target: return_block,
|
||||
unwind: UnwindAction::Continue,
|
||||
};
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
|
||||
// Create a block to destroy an unresumed generators. This can only destroy upvars.
|
||||
|
@ -1670,7 +1678,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
|||
args,
|
||||
destination,
|
||||
target: Some(_),
|
||||
cleanup: _,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
|
@ -1693,7 +1701,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
|||
| TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
@ -453,7 +453,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
} 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();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Call { args, destination, cleanup, .. } => {
|
||||
TerminatorKind::Call { args, destination, unwind, .. } => {
|
||||
// If the call is something like `a[*i] = f(i)`, where
|
||||
// `i : &mut usize`, then just duplicating the `a[*i]`
|
||||
// Place could result in two different locations if `f`
|
||||
|
@ -571,7 +571,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
destination: destination_local,
|
||||
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
||||
callsite,
|
||||
cleanup_block: cleanup,
|
||||
cleanup_block: unwind,
|
||||
in_cleanup_block: false,
|
||||
tcx: self.tcx,
|
||||
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);
|
||||
if ty.needs_drop(tcx, self.param_env) {
|
||||
self.cost += CALL_PENALTY;
|
||||
if unwind.is_some() {
|
||||
if let UnwindAction::Cleanup(_) = unwind {
|
||||
self.cost += LANDINGPAD_PENALTY;
|
||||
}
|
||||
} else {
|
||||
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());
|
||||
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
|
||||
|
@ -828,20 +828,20 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
|||
} else {
|
||||
CALL_PENALTY
|
||||
};
|
||||
if cleanup.is_some() {
|
||||
if let UnwindAction::Cleanup(_) = unwind {
|
||||
self.cost += LANDINGPAD_PENALTY;
|
||||
}
|
||||
}
|
||||
TerminatorKind::Assert { cleanup, .. } => {
|
||||
TerminatorKind::Assert { unwind, .. } => {
|
||||
self.cost += CALL_PENALTY;
|
||||
if cleanup.is_some() {
|
||||
if let UnwindAction::Cleanup(_) = unwind {
|
||||
self.cost += LANDINGPAD_PENALTY;
|
||||
}
|
||||
}
|
||||
TerminatorKind::Resume => self.cost += RESUME_PENALTY,
|
||||
TerminatorKind::InlineAsm { cleanup, .. } => {
|
||||
TerminatorKind::InlineAsm { unwind, .. } => {
|
||||
self.cost += INSTR_COST;
|
||||
if cleanup.is_some() {
|
||||
if let UnwindAction::Cleanup(_) = unwind {
|
||||
self.cost += LANDINGPAD_PENALTY;
|
||||
}
|
||||
}
|
||||
|
@ -979,7 +979,7 @@ struct Integrator<'a, 'tcx> {
|
|||
destination: Local,
|
||||
callsite_scope: SourceScopeData<'tcx>,
|
||||
callsite: &'a CallSite<'tcx>,
|
||||
cleanup_block: Option<BasicBlock>,
|
||||
cleanup_block: UnwindAction,
|
||||
in_cleanup_block: bool,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
expn_data: LocalExpnId,
|
||||
|
@ -1014,18 +1014,21 @@ impl Integrator<'_, '_> {
|
|||
new
|
||||
}
|
||||
|
||||
fn map_unwind(&self, unwind: Option<BasicBlock>) -> Option<BasicBlock> {
|
||||
fn map_unwind(&self, unwind: UnwindAction) -> UnwindAction {
|
||||
if self.in_cleanup_block {
|
||||
if unwind.is_some() {
|
||||
bug!("cleanup on cleanup block");
|
||||
match unwind {
|
||||
UnwindAction::Cleanup(_) | UnwindAction::Continue => {
|
||||
bug!("cleanup on cleanup block");
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => return unwind,
|
||||
}
|
||||
return unwind;
|
||||
}
|
||||
|
||||
match unwind {
|
||||
Some(target) => Some(self.map_block(target)),
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => unwind,
|
||||
UnwindAction::Cleanup(target) => UnwindAction::Cleanup(self.map_block(target)),
|
||||
// Add an unwind edge to the original call's cleanup block
|
||||
None => self.cleanup_block,
|
||||
UnwindAction::Continue => self.cleanup_block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1116,15 +1119,15 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
|||
*target = self.map_block(*target);
|
||||
*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 {
|
||||
*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);
|
||||
*cleanup = self.map_unwind(*cleanup);
|
||||
*unwind = self.map_unwind(*unwind);
|
||||
}
|
||||
TerminatorKind::Return => {
|
||||
terminator.kind = if let Some(tgt) = self.callsite.target {
|
||||
|
@ -1134,11 +1137,14 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Resume => {
|
||||
if let Some(tgt) = self.cleanup_block {
|
||||
terminator.kind = TerminatorKind::Goto { target: tgt }
|
||||
}
|
||||
terminator.kind = match self.cleanup_block {
|
||||
UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt },
|
||||
UnwindAction::Continue => TerminatorKind::Resume,
|
||||
UnwindAction::Unreachable => TerminatorKind::Unreachable,
|
||||
UnwindAction::Terminate => TerminatorKind::Terminate,
|
||||
};
|
||||
}
|
||||
TerminatorKind::Abort => {}
|
||||
TerminatorKind::Terminate => {}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||
*real_target = self.map_block(*real_target);
|
||||
|
@ -1149,11 +1155,11 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
|||
{
|
||||
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 {
|
||||
*tgt = self.map_block(*tgt);
|
||||
}
|
||||
*cleanup = self.map_unwind(*cleanup);
|
||||
*unwind = self.map_unwind(*unwind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
|||
ref mut args,
|
||||
destination,
|
||||
target,
|
||||
cleanup,
|
||||
unwind,
|
||||
fn_span,
|
||||
..
|
||||
} if let ty::FnDef(def_id, _) = *literal.ty().kind()
|
||||
|
@ -196,7 +196,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
|||
};
|
||||
method(place)
|
||||
}).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 };
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ fn lower_slice_len_call<'tcx>(
|
|||
args,
|
||||
destination,
|
||||
target: Some(bb),
|
||||
cleanup: None,
|
||||
from_hir_call: true,
|
||||
..
|
||||
} => {
|
||||
|
|
|
@ -72,7 +72,7 @@ impl RemoveNoopLandingPads {
|
|||
TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
@ -103,11 +103,11 @@ impl RemoveNoopLandingPads {
|
|||
for bb in postorder {
|
||||
debug!(" processing {:?}", bb);
|
||||
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) {
|
||||
debug!(" removing noop landing pad");
|
||||
landing_pads_removed += 1;
|
||||
*unwind = None;
|
||||
*unwind = UnwindAction::Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
|||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::InlineAsm { .. }
|
||||
|
@ -164,7 +164,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
|||
}
|
||||
|
||||
TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Terminate
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
|
@ -499,7 +499,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
|||
args: vec![Operand::Move(ref_loc)],
|
||||
destination: dest,
|
||||
target: Some(next),
|
||||
cleanup: Some(cleanup),
|
||||
unwind: UnwindAction::Cleanup(cleanup),
|
||||
from_hir_call: true,
|
||||
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.block(
|
||||
vec![],
|
||||
TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None },
|
||||
TerminatorKind::Drop {
|
||||
place: dest_field,
|
||||
target: unwind,
|
||||
unwind: UnwindAction::Terminate,
|
||||
},
|
||||
true,
|
||||
);
|
||||
unwind = next_unwind;
|
||||
|
@ -776,10 +780,10 @@ fn build_call_shim<'tcx>(
|
|||
args,
|
||||
destination: Place::return_place(),
|
||||
target: Some(BasicBlock::new(1)),
|
||||
cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
||||
Some(BasicBlock::new(3))
|
||||
unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
||||
UnwindAction::Cleanup(BasicBlock::new(3))
|
||||
} else {
|
||||
None
|
||||
UnwindAction::Continue
|
||||
},
|
||||
from_hir_call: true,
|
||||
fn_span: span,
|
||||
|
@ -792,7 +796,11 @@ fn build_call_shim<'tcx>(
|
|||
block(
|
||||
&mut blocks,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
@ -803,7 +811,11 @@ fn build_call_shim<'tcx>(
|
|||
block(
|
||||
&mut blocks,
|
||||
vec![],
|
||||
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
|
||||
TerminatorKind::Drop {
|
||||
place: rcvr_place(),
|
||||
target: BasicBlock::new(4),
|
||||
unwind: UnwindAction::Terminate,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue