Skip to content

Commit 4c53783

Browse files
committed
when terminating during unwinding, show the reason why
1 parent 0b31792 commit 4c53783

File tree

88 files changed

+383
-281
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+383
-281
lines changed

compiler/rustc_borrowck/src/invalidation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
202202
}
203203
}
204204
TerminatorKind::Goto { target: _ }
205-
| TerminatorKind::UnwindTerminate
205+
| TerminatorKind::UnwindTerminate(_)
206206
| TerminatorKind::Unreachable
207207
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
208208
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {

compiler/rustc_borrowck/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
770770
}
771771

772772
TerminatorKind::Goto { target: _ }
773-
| TerminatorKind::UnwindTerminate
773+
| TerminatorKind::UnwindTerminate(_)
774774
| TerminatorKind::Unreachable
775775
| TerminatorKind::UnwindResume
776776
| TerminatorKind::Return
@@ -817,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
817817
}
818818
}
819819

820-
TerminatorKind::UnwindTerminate
820+
TerminatorKind::UnwindTerminate(_)
821821
| TerminatorKind::Assert { .. }
822822
| TerminatorKind::Call { .. }
823823
| TerminatorKind::Drop { .. }

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13341334
match &term.kind {
13351335
TerminatorKind::Goto { .. }
13361336
| TerminatorKind::UnwindResume
1337-
| TerminatorKind::UnwindTerminate
1337+
| TerminatorKind::UnwindTerminate(_)
13381338
| TerminatorKind::Return
13391339
| TerminatorKind::GeneratorDrop
13401340
| TerminatorKind::Unreachable
@@ -1613,7 +1613,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16131613
span_mirbug!(self, block_data, "resume on non-cleanup block!")
16141614
}
16151615
}
1616-
TerminatorKind::UnwindTerminate => {
1616+
TerminatorKind::UnwindTerminate(_) => {
16171617
if !is_cleanup {
16181618
span_mirbug!(self, block_data, "abort on non-cleanup block!")
16191619
}
@@ -1697,7 +1697,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16971697
span_mirbug!(self, ctxt, "unwind on cleanup block")
16981698
}
16991699
}
1700-
UnwindAction::Unreachable | UnwindAction::Terminate => (),
1700+
UnwindAction::Unreachable | UnwindAction::Terminate(_) => (),
17011701
}
17021702
}
17031703

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,8 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
474474
*destination,
475475
);
476476
}
477-
TerminatorKind::UnwindTerminate => {
478-
codegen_panic_cannot_unwind(fx, source_info);
477+
TerminatorKind::UnwindTerminate(reason) => {
478+
codegen_unwind_terminate(fx, source_info, *reason);
479479
}
480480
TerminatorKind::UnwindResume => {
481481
// FIXME implement unwinding
@@ -971,13 +971,14 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
971971
codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
972972
}
973973

974-
pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
974+
pub(crate) fn codegen_unwind_terminate<'tcx>(
975975
fx: &mut FunctionCx<'_, '_, 'tcx>,
976976
source_info: mir::SourceInfo,
977+
reason: UnwindTerminateReason,
977978
) {
978979
let args = [];
979980

980-
codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
981+
codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span);
981982
}
982983

983984
fn codegen_panic_inner<'tcx>(

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
551551
TerminatorKind::Goto { .. }
552552
| TerminatorKind::SwitchInt { .. }
553553
| TerminatorKind::UnwindResume
554-
| TerminatorKind::UnwindTerminate
554+
| TerminatorKind::UnwindTerminate(_)
555555
| TerminatorKind::Return
556556
| TerminatorKind::Unreachable
557557
| TerminatorKind::Drop { .. }

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
285285
match data.terminator().kind {
286286
TerminatorKind::Goto { .. }
287287
| TerminatorKind::UnwindResume
288-
| TerminatorKind::UnwindTerminate
288+
| TerminatorKind::UnwindTerminate(_)
289289
| TerminatorKind::Return
290290
| TerminatorKind::GeneratorDrop
291291
| TerminatorKind::Unreachable

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::MemFlags;
1212
use rustc_ast as ast;
1313
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
15+
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
1616
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1717
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1818
use rustc_middle::ty::{self, Instance, Ty};
@@ -178,7 +178,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
178178
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
179179
mir::UnwindAction::Continue => None,
180180
mir::UnwindAction::Unreachable => None,
181-
mir::UnwindAction::Terminate => {
181+
mir::UnwindAction::Terminate(reason) => {
182182
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
183183
// MSVC SEH will abort automatically if an exception tries to
184184
// propagate out from cleanup.
@@ -191,7 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
191191

192192
None
193193
} else {
194-
Some(fx.terminate_block())
194+
Some(fx.terminate_block(reason))
195195
}
196196
}
197197
};
@@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264264
) -> MergingSucc {
265265
let unwind_target = match unwind {
266266
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
267-
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
267+
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
268268
mir::UnwindAction::Continue => None,
269269
mir::UnwindAction::Unreachable => None,
270270
};
@@ -649,12 +649,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
649649
helper: TerminatorCodegenHelper<'tcx>,
650650
bx: &mut Bx,
651651
terminator: &mir::Terminator<'tcx>,
652+
reason: UnwindTerminateReason,
652653
) {
653654
let span = terminator.source_info.span;
654655
self.set_debug_loc(bx, terminator.source_info);
655656

656657
// Obtain the panic entry point.
657-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
658+
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
658659

659660
// Codegen the actual panic invoke/call.
660661
let merging_succ = helper.do_call(
@@ -1229,8 +1230,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12291230
MergingSucc::False
12301231
}
12311232

1232-
mir::TerminatorKind::UnwindTerminate => {
1233-
self.codegen_terminate_terminator(helper, bx, terminator);
1233+
mir::TerminatorKind::UnwindTerminate(reason) => {
1234+
self.codegen_terminate_terminator(helper, bx, terminator, reason);
12341235
MergingSucc::False
12351236
}
12361237

@@ -1579,79 +1580,83 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15791580
})
15801581
}
15811582

1582-
fn terminate_block(&mut self) -> Bx::BasicBlock {
1583-
self.terminate_block.unwrap_or_else(|| {
1584-
let funclet;
1585-
let llbb;
1586-
let mut bx;
1587-
if base::wants_msvc_seh(self.cx.sess()) {
1588-
// This is a basic block that we're aborting the program for,
1589-
// notably in an `extern` function. These basic blocks are inserted
1590-
// so that we assert that `extern` functions do indeed not panic,
1591-
// and if they do we abort the process.
1592-
//
1593-
// On MSVC these are tricky though (where we're doing funclets). If
1594-
// we were to do a cleanuppad (like below) the normal functions like
1595-
// `longjmp` would trigger the abort logic, terminating the
1596-
// program. Instead we insert the equivalent of `catch(...)` for C++
1597-
// which magically doesn't trigger when `longjmp` files over this
1598-
// frame.
1599-
//
1600-
// Lots more discussion can be found on #48251 but this codegen is
1601-
// modeled after clang's for:
1602-
//
1603-
// try {
1604-
// foo();
1605-
// } catch (...) {
1606-
// bar();
1607-
// }
1608-
//
1609-
// which creates an IR snippet like
1610-
//
1611-
// cs_terminate:
1612-
// %cs = catchswitch within none [%cp_terminate] unwind to caller
1613-
// cp_terminate:
1614-
// %cp = catchpad within %cs [null, i32 64, null]
1615-
// ...
1616-
1617-
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
1618-
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
1619-
1620-
let mut cs_bx = Bx::build(self.cx, llbb);
1621-
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
1622-
1623-
// The "null" here is actually a RTTI type descriptor for the
1624-
// C++ personality function, but `catch (...)` has no type so
1625-
// it's null. The 64 here is actually a bitfield which
1626-
// represents that this is a catch-all block.
1627-
bx = Bx::build(self.cx, cp_llbb);
1628-
let null =
1629-
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
1630-
let sixty_four = bx.const_i32(64);
1631-
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
1632-
} else {
1633-
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
1634-
bx = Bx::build(self.cx, llbb);
1583+
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
1584+
if let Some(bb) = self.terminate_in_cleanup_block && reason == UnwindTerminateReason::InCleanup {
1585+
return bb;
1586+
}
1587+
1588+
let funclet;
1589+
let llbb;
1590+
let mut bx;
1591+
if base::wants_msvc_seh(self.cx.sess()) {
1592+
// This is a basic block that we're aborting the program for,
1593+
// notably in an `extern` function. These basic blocks are inserted
1594+
// so that we assert that `extern` functions do indeed not panic,
1595+
// and if they do we abort the process.
1596+
//
1597+
// On MSVC these are tricky though (where we're doing funclets). If
1598+
// we were to do a cleanuppad (like below) the normal functions like
1599+
// `longjmp` would trigger the abort logic, terminating the
1600+
// program. Instead we insert the equivalent of `catch(...)` for C++
1601+
// which magically doesn't trigger when `longjmp` files over this
1602+
// frame.
1603+
//
1604+
// Lots more discussion can be found on #48251 but this codegen is
1605+
// modeled after clang's for:
1606+
//
1607+
// try {
1608+
// foo();
1609+
// } catch (...) {
1610+
// bar();
1611+
// }
1612+
//
1613+
// which creates an IR snippet like
1614+
//
1615+
// cs_terminate:
1616+
// %cs = catchswitch within none [%cp_terminate] unwind to caller
1617+
// cp_terminate:
1618+
// %cp = catchpad within %cs [null, i32 64, null]
1619+
// ...
1620+
1621+
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
1622+
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
1623+
1624+
let mut cs_bx = Bx::build(self.cx, llbb);
1625+
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
1626+
1627+
// The "null" here is actually a RTTI type descriptor for the
1628+
// C++ personality function, but `catch (...)` has no type so
1629+
// it's null. The 64 here is actually a bitfield which
1630+
// represents that this is a catch-all block.
1631+
bx = Bx::build(self.cx, cp_llbb);
1632+
let null =
1633+
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
1634+
let sixty_four = bx.const_i32(64);
1635+
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
1636+
} else {
1637+
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
1638+
bx = Bx::build(self.cx, llbb);
16351639

1636-
let llpersonality = self.cx.eh_personality();
1637-
bx.filter_landing_pad(llpersonality);
1640+
let llpersonality = self.cx.eh_personality();
1641+
bx.filter_landing_pad(llpersonality);
16381642

1639-
funclet = None;
1640-
}
1643+
funclet = None;
1644+
}
16411645

1642-
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
1646+
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
16431647

1644-
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
1645-
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
1648+
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
1649+
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
16461650

1647-
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
1648-
bx.do_not_inline(llret);
1651+
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
1652+
bx.do_not_inline(llret);
16491653

1650-
bx.unreachable();
1654+
bx.unreachable();
16511655

1652-
self.terminate_block = Some(llbb);
1653-
llbb
1654-
})
1656+
if reason == UnwindTerminateReason::InCleanup {
1657+
self.terminate_in_cleanup_block = Some(llbb);
1658+
}
1659+
llbb
16551660
}
16561661

16571662
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
8383
/// Cached unreachable block
8484
unreachable_block: Option<Bx::BasicBlock>,
8585

86-
/// Cached terminate upon unwinding block
87-
terminate_block: Option<Bx::BasicBlock>,
86+
/// Cached terminate upon unwinding (reason: InCleanup) block
87+
terminate_in_cleanup_block: Option<Bx::BasicBlock>,
8888

8989
/// The location where each MIR arg/var/tmp/ret is stored. This is
9090
/// usually an `PlaceRef` representing an alloca, but not always:
@@ -174,7 +174,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
174174
let mut start_bx = Bx::build(cx, start_llbb);
175175

176176
if mir.basic_blocks.iter().any(|bb| {
177-
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
177+
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
178178
}) {
179179
start_bx.set_personality_fn(cx.eh_personality());
180180
}
@@ -199,7 +199,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
199199
personality_slot: None,
200200
cached_llbbs,
201201
unreachable_block: None,
202-
terminate_block: None,
202+
terminate_in_cleanup_block: None,
203203
cleanup_kinds,
204204
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
205205
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,16 +756,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
756756
///
757757
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
758758
/// unwinding, and doing so is UB.
759+
#[cold] // usually we have normal returns, not unwinding
759760
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
760761
self.frame_mut().loc = match target {
761762
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
762763
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
763764
mir::UnwindAction::Unreachable => {
764765
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
765766
}
766-
mir::UnwindAction::Terminate => {
767+
mir::UnwindAction::Terminate(reason) => {
767768
self.frame_mut().loc = Right(self.frame_mut().body.span);
768-
M::unwind_terminate(self)?;
769+
M::unwind_terminate(self, reason)?;
769770
// This might have pushed a new stack frame, or it terminated execution.
770771
// Either way, `loc` will not be updated.
771772
return Ok(());

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,10 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
222222
fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>;
223223

224224
/// Called when unwinding reached a state where execution should be terminated.
225-
fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
225+
fn unwind_terminate(
226+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
227+
reason: mir::UnwindTerminateReason,
228+
) -> InterpResult<'tcx>;
226229

227230
/// Called for all binary operations where the LHS has pointer type.
228231
///
@@ -462,6 +465,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
462465

463466
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
464467
/// The `locals` have already been destroyed!
468+
#[inline(always)]
465469
fn after_stack_pop(
466470
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
467471
_frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
@@ -501,7 +505,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
501505
}
502506

503507
#[inline(always)]
504-
fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> {
508+
fn unwind_terminate(
509+
_ecx: &mut InterpCx<$mir, $tcx, Self>,
510+
_reason: mir::UnwindTerminateReason,
511+
) -> InterpResult<$tcx> {
505512
unreachable!("unwinding cannot happen during compile-time evaluation")
506513
}
507514

0 commit comments

Comments
 (0)