mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
when terminating during unwinding, show the reason why
This commit is contained in:
parent
0b31792ef1
commit
4c53783f3c
@ -202,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
||||
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
|
||||
|
@ -770,7 +770,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||
}
|
||||
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::Return
|
||||
@ -817,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||
}
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
@ -1334,7 +1334,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
match &term.kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
@ -1613,7 +1613,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
span_mirbug!(self, block_data, "resume on non-cleanup block!")
|
||||
}
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
if !is_cleanup {
|
||||
span_mirbug!(self, block_data, "abort on non-cleanup block!")
|
||||
}
|
||||
@ -1697,7 +1697,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
span_mirbug!(self, ctxt, "unwind on cleanup block")
|
||||
}
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,8 +474,8 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||
*destination,
|
||||
);
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
codegen_panic_cannot_unwind(fx, source_info);
|
||||
TerminatorKind::UnwindTerminate(reason) => {
|
||||
codegen_unwind_terminate(fx, source_info, *reason);
|
||||
}
|
||||
TerminatorKind::UnwindResume => {
|
||||
// FIXME implement unwinding
|
||||
@ -971,13 +971,14 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
|
||||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
|
||||
pub(crate) fn codegen_unwind_terminate<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
source_info: mir::SourceInfo,
|
||||
reason: UnwindTerminateReason,
|
||||
) {
|
||||
let args = [];
|
||||
|
||||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
|
||||
codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span);
|
||||
}
|
||||
|
||||
fn codegen_panic_inner<'tcx>(
|
||||
|
@ -551,7 +551,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
@ -285,7 +285,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||
match data.terminator().kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
|
@ -12,7 +12,7 @@ use crate::MemFlags;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
@ -178,7 +178,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
mir::UnwindAction::Terminate => {
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
|
||||
// MSVC SEH will abort automatically if an exception tries to
|
||||
// propagate out from cleanup.
|
||||
@ -191,7 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
|
||||
None
|
||||
} else {
|
||||
Some(fx.terminate_block())
|
||||
Some(fx.terminate_block(reason))
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
) -> MergingSucc {
|
||||
let unwind_target = match unwind {
|
||||
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
|
||||
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
};
|
||||
@ -649,12 +649,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
helper: TerminatorCodegenHelper<'tcx>,
|
||||
bx: &mut Bx,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
reason: UnwindTerminateReason,
|
||||
) {
|
||||
let span = terminator.source_info.span;
|
||||
self.set_debug_loc(bx, terminator.source_info);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
let merging_succ = helper.do_call(
|
||||
@ -1229,8 +1230,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
MergingSucc::False
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate => {
|
||||
self.codegen_terminate_terminator(helper, bx, terminator);
|
||||
mir::TerminatorKind::UnwindTerminate(reason) => {
|
||||
self.codegen_terminate_terminator(helper, bx, terminator, reason);
|
||||
MergingSucc::False
|
||||
}
|
||||
|
||||
@ -1579,79 +1580,83 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn terminate_block(&mut self) -> Bx::BasicBlock {
|
||||
self.terminate_block.unwrap_or_else(|| {
|
||||
let funclet;
|
||||
let llbb;
|
||||
let mut bx;
|
||||
if base::wants_msvc_seh(self.cx.sess()) {
|
||||
// This is a basic block that we're aborting the program for,
|
||||
// notably in an `extern` function. These basic blocks are inserted
|
||||
// so that we assert that `extern` functions do indeed not panic,
|
||||
// and if they do we abort the process.
|
||||
//
|
||||
// On MSVC these are tricky though (where we're doing funclets). If
|
||||
// we were to do a cleanuppad (like below) the normal functions like
|
||||
// `longjmp` would trigger the abort logic, terminating the
|
||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||
// which magically doesn't trigger when `longjmp` files over this
|
||||
// frame.
|
||||
//
|
||||
// Lots more discussion can be found on #48251 but this codegen is
|
||||
// modeled after clang's for:
|
||||
//
|
||||
// try {
|
||||
// foo();
|
||||
// } catch (...) {
|
||||
// bar();
|
||||
// }
|
||||
//
|
||||
// which creates an IR snippet like
|
||||
//
|
||||
// cs_terminate:
|
||||
// %cs = catchswitch within none [%cp_terminate] unwind to caller
|
||||
// cp_terminate:
|
||||
// %cp = catchpad within %cs [null, i32 64, null]
|
||||
// ...
|
||||
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
||||
if let Some(bb) = self.terminate_in_cleanup_block && reason == UnwindTerminateReason::InCleanup {
|
||||
return bb;
|
||||
}
|
||||
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
let funclet;
|
||||
let llbb;
|
||||
let mut bx;
|
||||
if base::wants_msvc_seh(self.cx.sess()) {
|
||||
// This is a basic block that we're aborting the program for,
|
||||
// notably in an `extern` function. These basic blocks are inserted
|
||||
// so that we assert that `extern` functions do indeed not panic,
|
||||
// and if they do we abort the process.
|
||||
//
|
||||
// On MSVC these are tricky though (where we're doing funclets). If
|
||||
// we were to do a cleanuppad (like below) the normal functions like
|
||||
// `longjmp` would trigger the abort logic, terminating the
|
||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||
// which magically doesn't trigger when `longjmp` files over this
|
||||
// frame.
|
||||
//
|
||||
// Lots more discussion can be found on #48251 but this codegen is
|
||||
// modeled after clang's for:
|
||||
//
|
||||
// try {
|
||||
// foo();
|
||||
// } catch (...) {
|
||||
// bar();
|
||||
// }
|
||||
//
|
||||
// which creates an IR snippet like
|
||||
//
|
||||
// cs_terminate:
|
||||
// %cs = catchswitch within none [%cp_terminate] unwind to caller
|
||||
// cp_terminate:
|
||||
// %cp = catchpad within %cs [null, i32 64, null]
|
||||
// ...
|
||||
|
||||
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
bx = Bx::build(self.cx, cp_llbb);
|
||||
let null =
|
||||
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
|
||||
let sixty_four = bx.const_i32(64);
|
||||
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
|
||||
} else {
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||
bx = Bx::build(self.cx, llbb);
|
||||
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
bx.filter_landing_pad(llpersonality);
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
bx = Bx::build(self.cx, cp_llbb);
|
||||
let null =
|
||||
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
|
||||
let sixty_four = bx.const_i32(64);
|
||||
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
|
||||
} else {
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||
bx = Bx::build(self.cx, llbb);
|
||||
|
||||
funclet = None;
|
||||
}
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
bx.filter_landing_pad(llpersonality);
|
||||
|
||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
funclet = None;
|
||||
}
|
||||
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
|
||||
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
bx.do_not_inline(llret);
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
||||
bx.unreachable();
|
||||
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
bx.do_not_inline(llret);
|
||||
|
||||
self.terminate_block = Some(llbb);
|
||||
llbb
|
||||
})
|
||||
bx.unreachable();
|
||||
|
||||
if reason == UnwindTerminateReason::InCleanup {
|
||||
self.terminate_in_cleanup_block = Some(llbb);
|
||||
}
|
||||
llbb
|
||||
}
|
||||
|
||||
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already
|
||||
|
@ -83,8 +83,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
/// Cached unreachable block
|
||||
unreachable_block: Option<Bx::BasicBlock>,
|
||||
|
||||
/// Cached terminate upon unwinding block
|
||||
terminate_block: Option<Bx::BasicBlock>,
|
||||
/// Cached terminate upon unwinding (reason: InCleanup) block
|
||||
terminate_in_cleanup_block: Option<Bx::BasicBlock>,
|
||||
|
||||
/// The location where each MIR arg/var/tmp/ret is stored. This is
|
||||
/// usually an `PlaceRef` representing an alloca, but not always:
|
||||
@ -174,7 +174,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
let mut start_bx = Bx::build(cx, start_llbb);
|
||||
|
||||
if mir.basic_blocks.iter().any(|bb| {
|
||||
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
|
||||
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
|
||||
}) {
|
||||
start_bx.set_personality_fn(cx.eh_personality());
|
||||
}
|
||||
@ -199,7 +199,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
personality_slot: None,
|
||||
cached_llbbs,
|
||||
unreachable_block: None,
|
||||
terminate_block: None,
|
||||
terminate_in_cleanup_block: None,
|
||||
cleanup_kinds,
|
||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||
|
@ -756,6 +756,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
///
|
||||
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
|
||||
/// unwinding, and doing so is UB.
|
||||
#[cold] // usually we have normal returns, not unwinding
|
||||
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||
self.frame_mut().loc = match target {
|
||||
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
@ -763,9 +764,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
mir::UnwindAction::Unreachable => {
|
||||
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
|
||||
}
|
||||
mir::UnwindAction::Terminate => {
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
self.frame_mut().loc = Right(self.frame_mut().body.span);
|
||||
M::unwind_terminate(self)?;
|
||||
M::unwind_terminate(self, reason)?;
|
||||
// This might have pushed a new stack frame, or it terminated execution.
|
||||
// Either way, `loc` will not be updated.
|
||||
return Ok(());
|
||||
|
@ -222,7 +222,10 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||
fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called when unwinding reached a state where execution should be terminated.
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
|
||||
fn unwind_terminate(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called for all binary operations where the LHS has pointer type.
|
||||
///
|
||||
@ -462,6 +465,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||
|
||||
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
|
||||
/// The `locals` have already been destroyed!
|
||||
#[inline(always)]
|
||||
fn after_stack_pop(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
|
||||
@ -501,7 +505,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> {
|
||||
fn unwind_terminate(
|
||||
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
||||
_reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<$tcx> {
|
||||
unreachable!("unwinding cannot happen during compile-time evaluation")
|
||||
}
|
||||
|
||||
|
@ -196,8 +196,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
UnwindTerminate => {
|
||||
M::unwind_terminate(self)?;
|
||||
UnwindTerminate(reason) => {
|
||||
M::unwind_terminate(self, reason)?;
|
||||
}
|
||||
|
||||
// When we encounter Resume, we've finished unwinding
|
||||
|
@ -1037,7 +1037,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
|
||||
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate
|
||||
mir::TerminatorKind::UnwindTerminate(_)
|
||||
| mir::TerminatorKind::Call { .. }
|
||||
| mir::TerminatorKind::Assert { .. }
|
||||
| mir::TerminatorKind::FalseEdge { .. }
|
||||
|
@ -10,8 +10,8 @@ use rustc_middle::mir::{
|
||||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||
MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
|
||||
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
|
||||
START_BLOCK,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo,
|
||||
VarDebugInfoContents, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
@ -274,7 +274,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
||||
self.fail(location, "`UnwindAction::Continue` in no-unwind function");
|
||||
}
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||
UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => {
|
||||
if !is_cleanup {
|
||||
self.fail(
|
||||
location,
|
||||
"`UnwindAction::Terminate(InCleanup)` in a non-cleanup block",
|
||||
);
|
||||
}
|
||||
}
|
||||
// These are allowed everywhere.
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -501,7 +510,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
||||
self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind")
|
||||
}
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
let bb = location.block;
|
||||
if !self.body.basic_blocks[bb].is_cleanup {
|
||||
self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block")
|
||||
@ -1233,7 +1242,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
| TerminatorKind::InlineAsm { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable => {}
|
||||
}
|
||||
|
@ -238,6 +238,7 @@ language_item_table! {
|
||||
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
|
||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
||||
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
|
||||
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);
|
||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
|
@ -14,7 +14,8 @@ pub struct MirPatch<'tcx> {
|
||||
resume_block: Option<BasicBlock>,
|
||||
// Only for unreachable in cleanup path.
|
||||
unreachable_cleanup_block: Option<BasicBlock>,
|
||||
terminate_block: Option<BasicBlock>,
|
||||
// Cached block for UnwindTerminate(InCleanup)
|
||||
terminate_in_cleanup_block: Option<BasicBlock>,
|
||||
body_span: Span,
|
||||
next_local: usize,
|
||||
}
|
||||
@ -29,19 +30,21 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
next_local: body.local_decls.len(),
|
||||
resume_block: None,
|
||||
unreachable_cleanup_block: None,
|
||||
terminate_block: None,
|
||||
terminate_in_cleanup_block: None,
|
||||
body_span: body.span,
|
||||
};
|
||||
|
||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
// Check if we already have a resume block
|
||||
if let TerminatorKind::UnwindResume = block.terminator().kind && block.statements.is_empty() {
|
||||
if matches!(block.terminator().kind, TerminatorKind::UnwindResume)
|
||||
&& block.statements.is_empty()
|
||||
{
|
||||
result.resume_block = Some(bb);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we already have an unreachable block
|
||||
if let TerminatorKind::Unreachable = block.terminator().kind
|
||||
if matches!(block.terminator().kind, TerminatorKind::Unreachable)
|
||||
&& block.statements.is_empty()
|
||||
&& block.is_cleanup
|
||||
{
|
||||
@ -50,8 +53,12 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
}
|
||||
|
||||
// Check if we already have a terminate block
|
||||
if let TerminatorKind::UnwindTerminate = block.terminator().kind && block.statements.is_empty() {
|
||||
result.terminate_block = Some(bb);
|
||||
if matches!(
|
||||
block.terminator().kind,
|
||||
TerminatorKind::UnwindTerminate(UnwindTerminateReason::InCleanup)
|
||||
) && block.statements.is_empty()
|
||||
{
|
||||
result.terminate_in_cleanup_block = Some(bb);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -93,8 +100,8 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
bb
|
||||
}
|
||||
|
||||
pub fn terminate_block(&mut self) -> BasicBlock {
|
||||
if let Some(bb) = self.terminate_block {
|
||||
pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
|
||||
if let Some(bb) = self.terminate_in_cleanup_block && reason == UnwindTerminateReason::InCleanup {
|
||||
return bb;
|
||||
}
|
||||
|
||||
@ -102,11 +109,13 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
statements: vec![],
|
||||
terminator: Some(Terminator {
|
||||
source_info: SourceInfo::outermost(self.body_span),
|
||||
kind: TerminatorKind::UnwindTerminate,
|
||||
kind: TerminatorKind::UnwindTerminate(reason),
|
||||
}),
|
||||
is_cleanup: true,
|
||||
});
|
||||
self.terminate_block = Some(bb);
|
||||
if reason == UnwindTerminateReason::InCleanup {
|
||||
self.terminate_in_cleanup_block = Some(bb);
|
||||
}
|
||||
bb
|
||||
}
|
||||
|
||||
|
@ -621,7 +621,7 @@ pub enum TerminatorKind<'tcx> {
|
||||
///
|
||||
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
|
||||
/// cleanup blocks.
|
||||
UnwindTerminate,
|
||||
UnwindTerminate(UnwindTerminateReason),
|
||||
|
||||
/// Returns from the function.
|
||||
///
|
||||
@ -813,7 +813,7 @@ impl TerminatorKind<'_> {
|
||||
TerminatorKind::Goto { .. } => "Goto",
|
||||
TerminatorKind::SwitchInt { .. } => "SwitchInt",
|
||||
TerminatorKind::UnwindResume => "UnwindResume",
|
||||
TerminatorKind::UnwindTerminate => "UnwindTerminate",
|
||||
TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
|
||||
TerminatorKind::Return => "Return",
|
||||
TerminatorKind::Unreachable => "Unreachable",
|
||||
TerminatorKind::Drop { .. } => "Drop",
|
||||
@ -842,11 +842,22 @@ pub enum UnwindAction {
|
||||
/// Terminates the execution if unwind happens.
|
||||
///
|
||||
/// Depending on the platform and situation this may cause a non-unwindable panic or abort.
|
||||
Terminate,
|
||||
Terminate(UnwindTerminateReason),
|
||||
/// Cleanups to be done.
|
||||
Cleanup(BasicBlock),
|
||||
}
|
||||
|
||||
/// The reason we are terminating the process during unwinding.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum UnwindTerminateReason {
|
||||
/// Unwinding is just not possible given the ABI of this function.
|
||||
Abi,
|
||||
/// We were already cleaning up for an ongoing unwind, and a *second*, *nested* unwind was
|
||||
/// triggered by the drop glue.
|
||||
InCleanup,
|
||||
}
|
||||
|
||||
/// Information about an assertion failure.
|
||||
#[derive(Clone, Hash, HashStable, PartialEq, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
|
||||
|
@ -1,3 +1,4 @@
|
||||
use rustc_hir::LangItem;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
|
||||
@ -100,6 +101,32 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
|
||||
|
||||
impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
|
||||
|
||||
impl UnwindAction {
|
||||
fn cleanup_block(self) -> Option<BasicBlock> {
|
||||
match self {
|
||||
UnwindAction::Cleanup(bb) => Some(bb),
|
||||
UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwindTerminateReason {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
// Keep this in sync with the messages in `core/src/panicking.rs`.
|
||||
match self {
|
||||
UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
|
||||
UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lang_item(self) -> LangItem {
|
||||
match self {
|
||||
UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
|
||||
UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Terminator<'tcx> {
|
||||
pub source_info: SourceInfo,
|
||||
@ -156,7 +183,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||
}
|
||||
UnwindResume
|
||||
| UnwindTerminate
|
||||
| UnwindTerminate(_)
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
@ -198,7 +225,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Some(t).into_iter().chain(&mut [])
|
||||
}
|
||||
UnwindResume
|
||||
| UnwindTerminate
|
||||
| UnwindTerminate(_)
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
@ -215,7 +242,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
@ -234,7 +261,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
@ -271,18 +298,27 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||
let labels = self.fmt_successor_labels();
|
||||
assert_eq!(successor_count, labels.len());
|
||||
|
||||
let unwind = match self.unwind() {
|
||||
// Not needed or included in successors
|
||||
None | Some(UnwindAction::Cleanup(_)) => None,
|
||||
Some(UnwindAction::Continue) => Some("unwind continue"),
|
||||
Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
|
||||
Some(UnwindAction::Terminate) => Some("unwind terminate"),
|
||||
// `Cleanup` is already included in successors
|
||||
let show_unwind = !matches!(self.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
||||
let fmt_unwind = |fmt: &mut Formatter<'_>| -> fmt::Result {
|
||||
match self.unwind() {
|
||||
// Not needed or included in successors
|
||||
None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
|
||||
Some(UnwindAction::Continue) => write!(fmt, "unwind continue"),
|
||||
Some(UnwindAction::Unreachable) => write!(fmt, "unwind unreachable"),
|
||||
Some(UnwindAction::Terminate(reason)) => {
|
||||
write!(fmt, "unwind terminate ({})", reason.as_str())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match (successor_count, unwind) {
|
||||
(0, None) => Ok(()),
|
||||
(0, Some(unwind)) => write!(fmt, " -> {unwind}"),
|
||||
(1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
||||
match (successor_count, show_unwind) {
|
||||
(0, false) => Ok(()),
|
||||
(0, true) => {
|
||||
write!(fmt, " -> ")?;
|
||||
fmt_unwind(fmt)
|
||||
}
|
||||
(1, false) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
||||
_ => {
|
||||
write!(fmt, " -> [")?;
|
||||
for (i, target) in self.successors().enumerate() {
|
||||
@ -291,8 +327,9 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||
}
|
||||
write!(fmt, "{}: {:?}", labels[i], target)?;
|
||||
}
|
||||
if let Some(unwind) = unwind {
|
||||
write!(fmt, ", {unwind}")?;
|
||||
if show_unwind {
|
||||
write!(fmt, ", ")?;
|
||||
fmt_unwind(fmt)?;
|
||||
}
|
||||
write!(fmt, "]")
|
||||
}
|
||||
@ -312,7 +349,9 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Return => write!(fmt, "return"),
|
||||
GeneratorDrop => write!(fmt, "generator_drop"),
|
||||
UnwindResume => write!(fmt, "resume"),
|
||||
UnwindTerminate => write!(fmt, "abort"),
|
||||
UnwindTerminate(reason) => {
|
||||
write!(fmt, "abort(\"{}\")", reason.as_str())
|
||||
}
|
||||
Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
|
||||
Unreachable => write!(fmt, "unreachable"),
|
||||
Drop { place, .. } => write!(fmt, "drop({place:?})"),
|
||||
@ -391,7 +430,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
||||
use self::TerminatorKind::*;
|
||||
match *self {
|
||||
Return | UnwindResume | UnwindTerminate | Unreachable | GeneratorDrop => vec![],
|
||||
Return | UnwindResume | UnwindTerminate(_) | Unreachable | GeneratorDrop => vec![],
|
||||
Goto { .. } => vec!["".into()],
|
||||
SwitchInt { ref targets, .. } => targets
|
||||
.values
|
||||
@ -443,7 +482,8 @@ pub enum TerminatorEdges<'mir, 'tcx> {
|
||||
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
|
||||
AssignOnReturn {
|
||||
return_: Option<BasicBlock>,
|
||||
unwind: UnwindAction,
|
||||
/// The cleanup block, if it exists.
|
||||
cleanup: Option<BasicBlock>,
|
||||
place: CallReturnPlaces<'mir, 'tcx>,
|
||||
},
|
||||
/// Special edge for `SwitchInt`.
|
||||
@ -486,7 +526,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
|
||||
use TerminatorKind::*;
|
||||
match *self {
|
||||
Return | UnwindResume | UnwindTerminate | GeneratorDrop | Unreachable => {
|
||||
Return | UnwindResume | UnwindTerminate(_) | GeneratorDrop | Unreachable => {
|
||||
TerminatorEdges::None
|
||||
}
|
||||
|
||||
@ -496,7 +536,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
| Drop { target, unwind, place: _, replace: _ }
|
||||
| FalseUnwind { real_target: target, unwind } => match unwind {
|
||||
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
|
||||
UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => {
|
||||
UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
|
||||
TerminatorEdges::Single(target)
|
||||
}
|
||||
},
|
||||
@ -508,7 +548,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Yield { resume: target, drop, resume_arg, value: _ } => {
|
||||
TerminatorEdges::AssignOnReturn {
|
||||
return_: Some(target),
|
||||
unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup),
|
||||
cleanup: drop,
|
||||
place: CallReturnPlaces::Yield(resume_arg),
|
||||
}
|
||||
}
|
||||
@ -516,7 +556,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
|
||||
TerminatorEdges::AssignOnReturn {
|
||||
return_: target,
|
||||
unwind,
|
||||
cleanup: unwind.cleanup_block(),
|
||||
place: CallReturnPlaces::Call(destination),
|
||||
}
|
||||
}
|
||||
@ -530,7 +570,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
unwind,
|
||||
} => TerminatorEdges::AssignOnReturn {
|
||||
return_: destination,
|
||||
unwind,
|
||||
cleanup: unwind.cleanup_block(),
|
||||
place: CallReturnPlaces::InlineAsm(operands),
|
||||
},
|
||||
|
||||
|
@ -470,7 +470,7 @@ macro_rules! make_mir_visitor {
|
||||
match kind {
|
||||
TerminatorKind::Goto { .. } |
|
||||
TerminatorKind::UnwindResume |
|
||||
TerminatorKind::UnwindTerminate |
|
||||
TerminatorKind::UnwindTerminate(_) |
|
||||
TerminatorKind::GeneratorDrop |
|
||||
TerminatorKind::Unreachable |
|
||||
TerminatorKind::FalseEdge { .. } |
|
||||
|
@ -370,7 +370,7 @@ impl DropTree {
|
||||
let terminator = TerminatorKind::Drop {
|
||||
target: blocks[drop_data.1].unwrap(),
|
||||
// The caller will handle this if needed.
|
||||
unwind: UnwindAction::Terminate,
|
||||
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
place: drop_data.0.local.into(),
|
||||
replace: false,
|
||||
};
|
||||
@ -1507,7 +1507,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Yield { .. }
|
||||
|
@ -186,7 +186,7 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx
|
||||
|
||||
match self.body[bb].terminator().kind {
|
||||
// These terminators return control flow to the caller.
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::Return
|
||||
|
@ -80,7 +80,7 @@ impl Unwind {
|
||||
fn into_action(self) -> UnwindAction {
|
||||
match self {
|
||||
Unwind::To(bb) => UnwindAction::Cleanup(bb),
|
||||
Unwind::InCleanup => UnwindAction::Terminate,
|
||||
Unwind::InCleanup => UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, UnwindAction,
|
||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
|
||||
};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
@ -486,10 +486,10 @@ impl Direction for Forward {
|
||||
propagate(target, exit_state);
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
TerminatorEdges::AssignOnReturn { return_, unwind, place } => {
|
||||
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
|
||||
// This must be done *first*, otherwise the unwind path will see the assignments.
|
||||
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||
propagate(unwind, exit_state);
|
||||
if let Some(cleanup) = cleanup {
|
||||
propagate(cleanup, exit_state);
|
||||
}
|
||||
if let Some(return_) = return_ {
|
||||
analysis.apply_call_return_effect(exit_state, bb, place);
|
||||
|
@ -131,7 +131,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
@ -291,7 +291,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
||||
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
@ -328,7 +328,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
@ -371,7 +371,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
// need recording.
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. } => {}
|
||||
|
@ -270,7 +270,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||
}
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
@ -104,7 +104,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||
|
||||
for id in calls_to_terminate {
|
||||
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = UnwindAction::Terminate;
|
||||
*cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
|
||||
for id in cleanups_to_remove {
|
||||
|
@ -53,8 +53,10 @@ impl AddCallGuards {
|
||||
kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
|
||||
source_info,
|
||||
}) if pred_count[*destination] > 1
|
||||
&& (matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate)
|
||||
|| self == &AllCallEdges) =>
|
||||
&& (matches!(
|
||||
unwind,
|
||||
UnwindAction::Cleanup(_) | UnwindAction::Terminate(_)
|
||||
) || self == &AllCallEdges) =>
|
||||
{
|
||||
// It's a critical edge, break it
|
||||
let call_guard = BasicBlockData {
|
||||
|
@ -58,7 +58,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
@ -679,7 +679,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||
// None of these have Operands to const-propagate.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
@ -116,7 +116,7 @@ impl CoverageGraph {
|
||||
|
||||
match term.kind {
|
||||
TerminatorKind::Return { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. } => {
|
||||
// The `bb` has more than one _outgoing_ edge, or exits the function. Save the
|
||||
|
@ -868,7 +868,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
|
||||
|
||||
// Retain spans from all other terminators
|
||||
TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
@ -648,7 +648,7 @@ impl WriteInfo {
|
||||
}
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable { .. } => (),
|
||||
TerminatorKind::Drop { .. } => {
|
||||
|
@ -362,8 +362,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
UnwindAction::Unreachable => {
|
||||
Unwind::To(self.patch.unreachable_cleanup_block())
|
||||
}
|
||||
UnwindAction::Terminate => {
|
||||
Unwind::To(self.patch.terminate_block())
|
||||
UnwindAction::Terminate(reason) => {
|
||||
debug_assert_ne!(
|
||||
reason,
|
||||
UnwindTerminateReason::InCleanup,
|
||||
"we are not in a cleanup block, InCleanup reason should be impossible"
|
||||
);
|
||||
Unwind::To(self.patch.terminate_block(reason))
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -496,7 +501,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
if let TerminatorKind::Call {
|
||||
destination,
|
||||
target: Some(_),
|
||||
unwind: UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate,
|
||||
unwind:
|
||||
UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_),
|
||||
..
|
||||
} = data.terminator().kind
|
||||
{
|
||||
|
@ -1091,7 +1091,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
UnwindAction::Cleanup(tgt) => tgt,
|
||||
UnwindAction::Continue => elaborator.patch.resume_block(),
|
||||
UnwindAction::Unreachable => elaborator.patch.unreachable_cleanup_block(),
|
||||
UnwindAction::Terminate => elaborator.patch.terminate_block(),
|
||||
UnwindAction::Terminate(reason) => elaborator.patch.terminate_block(reason),
|
||||
})
|
||||
};
|
||||
elaborate_drop(
|
||||
@ -1239,7 +1239,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||
// These never unwind.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
@ -1759,7 +1759,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||
| TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
@ -906,12 +906,12 @@ impl Integrator<'_, '_> {
|
||||
UnwindAction::Cleanup(_) | UnwindAction::Continue => {
|
||||
bug!("cleanup on cleanup block");
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => return unwind,
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(_) => return unwind,
|
||||
}
|
||||
}
|
||||
|
||||
match unwind {
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => unwind,
|
||||
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
|
||||
UnwindAction::Continue => self.cleanup_block,
|
||||
@ -1022,10 +1022,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||
UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt },
|
||||
UnwindAction::Continue => TerminatorKind::UnwindResume,
|
||||
UnwindAction::Unreachable => TerminatorKind::Unreachable,
|
||||
UnwindAction::Terminate => TerminatorKind::UnwindTerminate,
|
||||
UnwindAction::Terminate(reason) => TerminatorKind::UnwindTerminate(reason),
|
||||
};
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {}
|
||||
TerminatorKind::UnwindTerminate(_) => {}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||
*real_target = self.map_block(*real_target);
|
||||
|
@ -72,7 +72,7 @@ impl RemoveNoopLandingPads {
|
||||
TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
@ -114,7 +114,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::InlineAsm { .. }
|
||||
@ -166,7 +166,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
@ -570,10 +570,10 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
||||
TerminatorKind::Drop {
|
||||
place: dest_field,
|
||||
target: unwind,
|
||||
unwind: UnwindAction::Terminate,
|
||||
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
replace: false,
|
||||
},
|
||||
true,
|
||||
/* is_cleanup */ true,
|
||||
);
|
||||
unwind = next_unwind;
|
||||
}
|
||||
@ -851,10 +851,10 @@ fn build_call_shim<'tcx>(
|
||||
TerminatorKind::Drop {
|
||||
place: rcvr_place(),
|
||||
target: BasicBlock::new(4),
|
||||
unwind: UnwindAction::Terminate,
|
||||
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
replace: false,
|
||||
},
|
||||
true,
|
||||
/* is_cleanup */ true,
|
||||
);
|
||||
|
||||
// BB #4 - resume
|
||||
|
@ -737,6 +737,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
||||
let source = self.body.source_info(location).span;
|
||||
|
||||
let tcx = self.tcx;
|
||||
let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
|
||||
let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
|
||||
if should_codegen_locally(tcx, &instance) {
|
||||
this.output.push(create_fn_mono_item(tcx, instance, source));
|
||||
}
|
||||
};
|
||||
|
||||
match terminator.kind {
|
||||
mir::TerminatorKind::Call { ref func, .. } => {
|
||||
let callee_ty = func.ty(self.body, tcx);
|
||||
@ -771,19 +778,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
||||
mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
|
||||
_ => LangItem::Panic,
|
||||
};
|
||||
let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
|
||||
if should_codegen_locally(tcx, &instance) {
|
||||
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||
}
|
||||
push_mono_lang_item(self, lang_item);
|
||||
}
|
||||
mir::TerminatorKind::UnwindTerminate { .. } => {
|
||||
let instance = Instance::mono(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
|
||||
);
|
||||
if should_codegen_locally(tcx, &instance) {
|
||||
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||
}
|
||||
mir::TerminatorKind::UnwindTerminate(reason) => {
|
||||
push_mono_lang_item(self, reason.lang_item());
|
||||
}
|
||||
mir::TerminatorKind::Goto { .. }
|
||||
| mir::TerminatorKind::SwitchInt { .. }
|
||||
@ -796,14 +794,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
||||
| mir::TerminatorKind::FalseUnwind { .. } => bug!(),
|
||||
}
|
||||
|
||||
if let Some(mir::UnwindAction::Terminate) = terminator.unwind() {
|
||||
let instance = Instance::mono(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
|
||||
);
|
||||
if should_codegen_locally(tcx, &instance) {
|
||||
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||
}
|
||||
if let Some(mir::UnwindAction::Terminate(reason)) = terminator.unwind() {
|
||||
push_mono_lang_item(self, reason.lang_item());
|
||||
}
|
||||
|
||||
self.super_terminator(terminator, location);
|
||||
|
@ -590,7 +590,7 @@ impl<'tcx> Stable<'tcx> for mir::UnwindAction {
|
||||
match self {
|
||||
UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
|
||||
UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
|
||||
UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate,
|
||||
UnwindAction::Terminate(_) => stable_mir::mir::UnwindAction::Terminate,
|
||||
UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
|
||||
}
|
||||
}
|
||||
@ -788,7 +788,7 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
|
||||
otherwise: targets.otherwise().as_usize(),
|
||||
},
|
||||
UnwindResume => Terminator::Resume,
|
||||
UnwindTerminate => Terminator::Abort,
|
||||
UnwindTerminate(_) => Terminator::Abort,
|
||||
Return => Terminator::Return,
|
||||
Unreachable => Terminator::Unreachable,
|
||||
Drop { place, target, unwind, replace: _ } => Terminator::Drop {
|
||||
|
@ -1100,6 +1100,7 @@ symbols! {
|
||||
panic_handler,
|
||||
panic_impl,
|
||||
panic_implementation,
|
||||
panic_in_cleanup,
|
||||
panic_info,
|
||||
panic_location,
|
||||
panic_misaligned_pointer_dereference,
|
||||
|
@ -179,6 +179,8 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
|
||||
|
||||
/// Panic because we cannot unwind out of a function.
|
||||
///
|
||||
/// This is a separate function to avoid the codesize impact of each crate containing the string to
|
||||
/// pass to `panic_nounwind`.
|
||||
/// This function is called directly by the codegen backend, and must not have
|
||||
/// any extra arguments (including those synthesized by track_caller).
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
@ -189,6 +191,21 @@ fn panic_cannot_unwind() -> ! {
|
||||
panic_nounwind("panic in a function that cannot unwind")
|
||||
}
|
||||
|
||||
/// Panic because we are unwinding out of a destructor during cleanup.
|
||||
///
|
||||
/// This is a separate function to avoid the codesize impact of each crate containing the string to
|
||||
/// pass to `panic_nounwind`.
|
||||
/// This function is called directly by the codegen backend, and must not have
|
||||
/// any extra arguments (including those synthesized by track_caller).
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function
|
||||
#[rustc_nounwind]
|
||||
fn panic_in_cleanup() -> ! {
|
||||
panic_nounwind("panic in a destructor during cleanup")
|
||||
}
|
||||
|
||||
/// This function is used instead of panic_fmt in const eval.
|
||||
#[lang = "const_panic_fmt"]
|
||||
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
|
||||
|
@ -292,7 +292,7 @@ fn check_terminator<'tcx>(
|
||||
| TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable => Ok(()),
|
||||
TerminatorKind::Drop { place, .. } => {
|
||||
if !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) {
|
||||
|
@ -975,9 +975,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||
ecx.start_panic_nounwind(msg)
|
||||
}
|
||||
|
||||
fn unwind_terminate(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
|
||||
fn unwind_terminate(ecx: &mut InterpCx<'mir, 'tcx, Self>, reason: mir::UnwindTerminateReason) -> InterpResult<'tcx> {
|
||||
// Call the lang item.
|
||||
let panic = ecx.tcx.lang_items().panic_cannot_unwind().unwrap();
|
||||
let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap();
|
||||
let panic = ty::Instance::mono(ecx.tcx.tcx, panic);
|
||||
ecx.call_function(
|
||||
panic,
|
||||
|
@ -5,7 +5,7 @@ thread 'main' panicked at $DIR/double_panic.rs:LL:CC:
|
||||
second
|
||||
stack backtrace:
|
||||
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
|
||||
panic in a function that cannot unwind
|
||||
panic in a destructor during cleanup
|
||||
stack backtrace:
|
||||
thread caused non-unwinding panic. aborting.
|
||||
error: abnormal termination: the program aborted execution
|
||||
@ -20,7 +20,7 @@ LL | ABORT();
|
||||
= note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
|
||||
= note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
|
||||
= note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
|
||||
= note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC
|
||||
= note: inside `core::panicking::panic_in_cleanup` at RUSTLIB/core/src/panicking.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/double_panic.rs:LL:CC
|
||||
|
|
||||
|
@ -9,7 +9,7 @@ fn main() -> () {
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const ();
|
||||
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate];
|
||||
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate (panic in a function that cannot unwind)];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
bb2 (cleanup): {
|
||||
_5 = move _6;
|
||||
- drop(_6) -> [return: bb6, unwind terminate];
|
||||
- drop(_6) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb6;
|
||||
}
|
||||
|
||||
@ -71,12 +71,12 @@
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
- drop(_5) -> [return: bb7, unwind terminate];
|
||||
- drop(_5) -> [return: bb7, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb7;
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
- drop(_4) -> [return: bb8, unwind terminate];
|
||||
- drop(_4) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ fn main() -> () {
|
||||
|
||||
bb2 (cleanup): {
|
||||
_5 = move _6;
|
||||
drop(_6) -> [return: bb6, unwind terminate];
|
||||
drop(_6) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
@ -73,11 +73,11 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
drop(_5) -> [return: bb7, unwind terminate];
|
||||
drop(_5) -> [return: bb7, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
drop(_4) -> [return: bb8, unwind terminate];
|
||||
drop(_4) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
|
@ -54,15 +54,15 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
drop(_7) -> [return: bb7, unwind terminate];
|
||||
drop(_7) -> [return: bb7, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
drop(_1) -> [return: bb9, unwind terminate];
|
||||
drop(_1) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
drop(_5) -> [return: bb9, unwind terminate];
|
||||
drop(_5) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
|
@ -54,15 +54,15 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
drop(_7) -> [return: bb7, unwind terminate];
|
||||
drop(_7) -> [return: bb7, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
drop(_1) -> [return: bb9, unwind terminate];
|
||||
drop(_1) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
drop(_5) -> [return: bb9, unwind terminate];
|
||||
drop(_5) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
|
@ -62,7 +62,7 @@ fn droppy() -> () {
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_2) -> [return: bb5, unwind terminate];
|
||||
drop(_2) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -89,15 +89,15 @@ fn move_out_by_subslice() -> () {
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
drop(_1) -> [return: bb12, unwind terminate];
|
||||
drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb10 (cleanup): {
|
||||
drop(_7) -> [return: bb11, unwind terminate];
|
||||
drop(_7) -> [return: bb11, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
drop(_2) -> [return: bb12, unwind terminate];
|
||||
drop(_2) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb12 (cleanup): {
|
||||
|
@ -89,15 +89,15 @@ fn move_out_from_end() -> () {
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
drop(_1) -> [return: bb12, unwind terminate];
|
||||
drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb10 (cleanup): {
|
||||
drop(_7) -> [return: bb11, unwind terminate];
|
||||
drop(_7) -> [return: bb11, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
drop(_2) -> [return: bb12, unwind terminate];
|
||||
drop(_2) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb12 (cleanup): {
|
||||
|
@ -63,7 +63,7 @@
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_2) -> [return: bb5, unwind terminate];
|
||||
drop(_2) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_2) -> [return: bb5, unwind terminate];
|
||||
drop(_2) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_2) -> [return: bb5, unwind terminate];
|
||||
drop(_2) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -104,7 +104,7 @@ yields ()
|
||||
|
||||
bb13 (cleanup): {
|
||||
StorageDead(_3);
|
||||
drop(_1) -> [return: bb14, unwind terminate];
|
||||
drop(_1) -> [return: bb14, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb14 (cleanup): {
|
||||
@ -113,6 +113,6 @@ yields ()
|
||||
|
||||
bb15 (cleanup): {
|
||||
StorageDead(_3);
|
||||
drop(_1) -> [return: bb14, unwind terminate];
|
||||
drop(_1) -> [return: bb14, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
StorageLive(_1);
|
||||
- _1 = foo() -> [return: bb1, unwind unreachable];
|
||||
+ StorageLive(_2);
|
||||
+ asm!("", options(MAY_UNWIND)) -> [return: bb2, unwind terminate];
|
||||
+ asm!("", options(MAY_UNWIND)) -> [return: bb2, unwind terminate (panic in a function that cannot unwind)];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
|
@ -32,7 +32,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb3 (cleanup): {
|
||||
+ drop(_2) -> [return: bb4, unwind terminate];
|
||||
+ drop(_2) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb4 (cleanup): {
|
||||
|
@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_1) -> [return: bb4, unwind terminate];
|
||||
drop(_1) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -36,7 +36,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb3 (cleanup): {
|
||||
+ drop(_2) -> [return: bb4, unwind terminate];
|
||||
+ drop(_2) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb4 (cleanup): {
|
||||
|
@ -36,7 +36,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb3 (cleanup): {
|
||||
+ drop(_2) -> [return: bb4, unwind terminate];
|
||||
+ drop(_2) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb4 (cleanup): {
|
||||
|
@ -27,7 +27,7 @@
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_1) -> [return: bb4, unwind terminate];
|
||||
drop(_1) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_1) -> [return: bb4, unwind terminate];
|
||||
drop(_1) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -54,11 +54,11 @@
|
||||
+ }
|
||||
+
|
||||
+ bb4 (cleanup): {
|
||||
+ drop(_4) -> [return: bb5, unwind terminate];
|
||||
+ drop(_4) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb5 (cleanup): {
|
||||
+ drop(_2) -> [return: bb6, unwind terminate];
|
||||
+ drop(_2) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb6 (cleanup): {
|
||||
|
@ -37,7 +37,7 @@
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_1) -> [return: bb5, unwind terminate];
|
||||
drop(_1) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(_1) -> [return: bb5, unwind terminate];
|
||||
drop(_1) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
bb4 (cleanup): {
|
||||
_8 = &mut _3;
|
||||
_9 = <Box<[i32]> as Drop>::drop(move _8) -> [return: bb1, unwind terminate];
|
||||
_9 = <Box<[i32]> as Drop>::drop(move _8) -> [return: bb1, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,17 +40,17 @@
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
- drop(_3) -> [return: bb5, unwind terminate];
|
||||
- drop(_3) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
- drop(_4) -> [return: bb5, unwind terminate];
|
||||
- drop(_4) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
- drop(_2) -> [return: bb6, unwind terminate];
|
||||
- drop(_2) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb7 (cleanup): {
|
||||
+ drop(_2) -> [return: bb6, unwind terminate];
|
||||
+ drop(_2) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb8 (cleanup): {
|
||||
|
@ -40,17 +40,17 @@
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
- drop(_3) -> [return: bb5, unwind terminate];
|
||||
- drop(_3) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
- drop(_4) -> [return: bb5, unwind terminate];
|
||||
- drop(_4) -> [return: bb5, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
- drop(_2) -> [return: bb6, unwind terminate];
|
||||
- drop(_2) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb7 (cleanup): {
|
||||
+ drop(_2) -> [return: bb6, unwind terminate];
|
||||
+ drop(_2) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb8 (cleanup): {
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
bb3 (cleanup): {
|
||||
_2 = move _5;
|
||||
- drop(_5) -> [return: bb8, unwind terminate];
|
||||
- drop(_5) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
@ -70,17 +70,17 @@
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
- drop(_4) -> [return: bb8, unwind terminate];
|
||||
- drop(_4) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
- drop(_2) -> [return: bb9, unwind terminate];
|
||||
- drop(_2) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb9;
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
- drop(_1) -> [return: bb10, unwind terminate];
|
||||
- drop(_1) -> [return: bb10, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb12;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb11 (cleanup): {
|
||||
+ drop(_1) -> [return: bb10, unwind terminate];
|
||||
+ drop(_1) -> [return: bb10, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb12 (cleanup): {
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
bb3 (cleanup): {
|
||||
_2 = move _5;
|
||||
- drop(_5) -> [return: bb8, unwind terminate];
|
||||
- drop(_5) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
@ -70,17 +70,17 @@
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
- drop(_4) -> [return: bb8, unwind terminate];
|
||||
- drop(_4) -> [return: bb8, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb8;
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
- drop(_2) -> [return: bb9, unwind terminate];
|
||||
- drop(_2) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb9;
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
- drop(_1) -> [return: bb10, unwind terminate];
|
||||
- drop(_1) -> [return: bb10, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb12;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb11 (cleanup): {
|
||||
+ drop(_1) -> [return: bb10, unwind terminate];
|
||||
+ drop(_1) -> [return: bb10, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb12 (cleanup): {
|
||||
|
@ -58,7 +58,7 @@
|
||||
+ _8 = const true;
|
||||
+ _9 = const true;
|
||||
_1 = move _3;
|
||||
- drop(_3) -> [return: bb11, unwind terminate];
|
||||
- drop(_3) -> [return: bb11, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb11;
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
- drop(_1) -> [return: bb12, unwind terminate];
|
||||
- drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb12;
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb16 (cleanup): {
|
||||
+ drop(_1) -> [return: bb12, unwind terminate];
|
||||
+ drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb17: {
|
||||
|
@ -58,7 +58,7 @@
|
||||
+ _8 = const true;
|
||||
+ _9 = const true;
|
||||
_1 = move _3;
|
||||
- drop(_3) -> [return: bb11, unwind terminate];
|
||||
- drop(_3) -> [return: bb11, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb11;
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
- drop(_1) -> [return: bb12, unwind terminate];
|
||||
- drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ goto -> bb12;
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@
|
||||
+ }
|
||||
+
|
||||
+ bb16 (cleanup): {
|
||||
+ drop(_1) -> [return: bb12, unwind terminate];
|
||||
+ drop(_1) -> [return: bb12, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ }
|
||||
+
|
||||
+ bb17: {
|
||||
|
@ -100,11 +100,11 @@ fn test() -> Option<Box<u32>> {
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
drop(_1) -> [return: bb13, unwind terminate];
|
||||
drop(_1) -> [return: bb13, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb12 (cleanup): {
|
||||
drop(_5) -> [return: bb13, unwind terminate];
|
||||
drop(_5) -> [return: bb13, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb13 (cleanup): {
|
||||
|
@ -100,11 +100,11 @@ fn test() -> Option<Box<u32>> {
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
drop(_1) -> [return: bb13, unwind terminate];
|
||||
drop(_1) -> [return: bb13, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb12 (cleanup): {
|
||||
drop(_5) -> [return: bb13, unwind terminate];
|
||||
drop(_5) -> [return: bb13, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb13 (cleanup): {
|
||||
|
@ -28,7 +28,7 @@ fn bar(_1: Box<[T]>) -> () {
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_1) -> [return: bb4, unwind terminate];
|
||||
drop(_1) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -45,7 +45,7 @@ fn foo(_1: Box<[T]>) -> T {
|
||||
}
|
||||
|
||||
bb5 (cleanup): {
|
||||
drop(_1) -> [return: bb6, unwind terminate];
|
||||
drop(_1) -> [return: bb6, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
|
@ -243,7 +243,7 @@
|
||||
}
|
||||
|
||||
- bb25 (cleanup): {
|
||||
- drop(_2) -> [return: bb26, unwind terminate];
|
||||
- drop(_2) -> [return: bb26, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ bb22 (cleanup): {
|
||||
+ goto -> bb27;
|
||||
}
|
||||
|
@ -243,7 +243,7 @@
|
||||
}
|
||||
|
||||
- bb25 (cleanup): {
|
||||
- drop(_2) -> [return: bb26, unwind terminate];
|
||||
- drop(_2) -> [return: bb26, unwind terminate (panic in a destructor during cleanup)];
|
||||
+ bb22 (cleanup): {
|
||||
+ goto -> bb27;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_2) -> [return: bb4, unwind terminate];
|
||||
drop(_2) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -31,7 +31,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb3 (cleanup): {
|
||||
drop(_2) -> [return: bb4, unwind terminate];
|
||||
drop(_2) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -33,7 +33,7 @@ fn main() -> () {
|
||||
|
||||
bb1 (cleanup): {
|
||||
(_1.0: Aligned) = move _4;
|
||||
drop(_1) -> [return: bb3, unwind terminate];
|
||||
drop(_1) -> [return: bb3, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
|
@ -167,11 +167,11 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb7 (cleanup): {
|
||||
drop(_21) -> [return: bb9, unwind terminate];
|
||||
drop(_21) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb8 (cleanup): {
|
||||
drop(_5) -> [return: bb9, unwind terminate];
|
||||
drop(_5) -> [return: bb9, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
|
@ -24,7 +24,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
|
||||
bb3 (cleanup): {
|
||||
_4 = &raw mut (*_1)[_3];
|
||||
_3 = Add(move _3, const 1_usize);
|
||||
drop((*_4)) -> [return: bb4, unwind terminate];
|
||||
drop((*_4)) -> [return: bb4, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
|
@ -22,7 +22,7 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
|
||||
}
|
||||
|
||||
bb4 (cleanup): {
|
||||
drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb2, unwind terminate];
|
||||
drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb2, unwind terminate (panic in a destructor during cleanup)];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
|
Loading…
Reference in New Issue
Block a user