@@ -12,7 +12,7 @@ use crate::MemFlags;
1212use rustc_ast as ast;
1313use rustc_ast:: { InlineAsmOptions , InlineAsmTemplatePiece } ;
1414use rustc_hir:: lang_items:: LangItem ;
15- use rustc_middle:: mir:: { self , AssertKind , SwitchTargets } ;
15+ use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
1616use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
1717use rustc_middle:: ty:: print:: { with_no_trimmed_paths, with_no_visible_paths} ;
1818use 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,81 @@ 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 ( ( cached_bb, cached_reason) ) = self . terminate_block && reason == cached_reason {
1585+ return cached_bb;
1586+ }
16351587
1636- let llpersonality = self . cx . eh_personality ( ) ;
1637- bx. filter_landing_pad ( llpersonality) ;
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) ;
16381639
1639- funclet = None ;
1640- }
1640+ let llpersonality = self . cx . eh_personality ( ) ;
1641+ bx. filter_landing_pad ( llpersonality) ;
1642+
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+ self . terminate_block = Some ( ( llbb, reason) ) ;
1657+ llbb
16551658 }
16561659
16571660 /// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already
0 commit comments