@@ -170,22 +170,17 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
170170
171171 let unwind_block = match unwind {
172172 mir:: UnwindAction :: Cleanup ( cleanup) => Some ( self . llbb_with_cleanup ( fx, cleanup) ) ,
173- _ if fx. mir [ self . bb ] . is_cleanup
174- && fn_abi. can_unwind
175- && !base:: wants_msvc_seh ( fx. cx . tcx ( ) . sess ) =>
176- {
177- // Exception must not propagate out of the execution of a cleanup (doing so
178- // can cause undefined behaviour). We insert a double unwind guard for
179- // functions that can potentially unwind to protect against this.
180- //
181- // This is not necessary for SEH which does not use successive unwinding
182- // like Itanium EH. EH frames in SEH are different from normal function
183- // frames and SEH will abort automatically if an exception tries to
184- // propagate out from cleanup.
185- Some ( fx. double_unwind_guard ( ) )
186- }
187173 mir:: UnwindAction :: Continue => None ,
188174 mir:: UnwindAction :: Unreachable => None ,
175+ mir:: UnwindAction :: Terminate => {
176+ if fx. mir [ self . bb ] . is_cleanup && base:: wants_msvc_seh ( fx. cx . tcx ( ) . sess ) {
177+ // SEH will abort automatically if an exception tries to
178+ // propagate out from cleanup.
179+ None
180+ } else {
181+ Some ( fx. terminate_block ( ) )
182+ }
183+ }
189184 } ;
190185
191186 if let Some ( unwind_block) = unwind_block {
@@ -253,7 +248,14 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
253248 instance : Instance < ' _ > ,
254249 mergeable_succ : bool ,
255250 ) -> MergingSucc {
256- if let mir:: UnwindAction :: Cleanup ( cleanup) = unwind {
251+ let unwind_target = match unwind {
252+ mir:: UnwindAction :: Cleanup ( cleanup) => Some ( self . llbb_with_cleanup ( fx, cleanup) ) ,
253+ mir:: UnwindAction :: Terminate => Some ( fx. terminate_block ( ) ) ,
254+ mir:: UnwindAction :: Continue => None ,
255+ mir:: UnwindAction :: Unreachable => None ,
256+ } ;
257+
258+ if let Some ( cleanup) = unwind_target {
257259 let ret_llbb = if let Some ( target) = destination {
258260 fx. llbb ( target)
259261 } else {
@@ -266,7 +268,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
266268 options,
267269 line_spans,
268270 instance,
269- Some ( ( ret_llbb, self . llbb_with_cleanup ( fx , cleanup) , self . funclet ( fx) ) ) ,
271+ Some ( ( ret_llbb, cleanup, self . funclet ( fx) ) ) ,
270272 ) ;
271273 MergingSucc :: False
272274 } else {
@@ -1551,62 +1553,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15511553 fn landing_pad_for_uncached ( & mut self , bb : mir:: BasicBlock ) -> Bx :: BasicBlock {
15521554 let llbb = self . llbb ( bb) ;
15531555 if base:: wants_msvc_seh ( self . cx . sess ( ) ) {
1554- let funclet;
1555- let ret_llbb;
1556- match self . mir [ bb] . terminator . as_ref ( ) . map ( |t| & t. kind ) {
1557- // This is a basic block that we're aborting the program for,
1558- // notably in an `extern` function. These basic blocks are inserted
1559- // so that we assert that `extern` functions do indeed not panic,
1560- // and if they do we abort the process.
1561- //
1562- // On MSVC these are tricky though (where we're doing funclets). If
1563- // we were to do a cleanuppad (like below) the normal functions like
1564- // `longjmp` would trigger the abort logic, terminating the
1565- // program. Instead we insert the equivalent of `catch(...)` for C++
1566- // which magically doesn't trigger when `longjmp` files over this
1567- // frame.
1568- //
1569- // Lots more discussion can be found on #48251 but this codegen is
1570- // modeled after clang's for:
1571- //
1572- // try {
1573- // foo();
1574- // } catch (...) {
1575- // bar();
1576- // }
1577- Some ( & mir:: TerminatorKind :: Abort ) => {
1578- let cs_llbb =
1579- Bx :: append_block ( self . cx , self . llfn , & format ! ( "cs_funclet{:?}" , bb) ) ;
1580- let cp_llbb =
1581- Bx :: append_block ( self . cx , self . llfn , & format ! ( "cp_funclet{:?}" , bb) ) ;
1582- ret_llbb = cs_llbb;
1583-
1584- let mut cs_bx = Bx :: build ( self . cx , cs_llbb) ;
1585- let cs = cs_bx. catch_switch ( None , None , & [ cp_llbb] ) ;
1586-
1587- // The "null" here is actually a RTTI type descriptor for the
1588- // C++ personality function, but `catch (...)` has no type so
1589- // it's null. The 64 here is actually a bitfield which
1590- // represents that this is a catch-all block.
1591- let mut cp_bx = Bx :: build ( self . cx , cp_llbb) ;
1592- let null = cp_bx. const_null (
1593- cp_bx. type_i8p_ext ( cp_bx. cx ( ) . data_layout ( ) . instruction_address_space ) ,
1594- ) ;
1595- let sixty_four = cp_bx. const_i32 ( 64 ) ;
1596- funclet = cp_bx. catch_pad ( cs, & [ null, sixty_four, null] ) ;
1597- cp_bx. br ( llbb) ;
1598- }
1599- _ => {
1600- let cleanup_llbb =
1601- Bx :: append_block ( self . cx , self . llfn , & format ! ( "funclet_{:?}" , bb) ) ;
1602- ret_llbb = cleanup_llbb;
1603- let mut cleanup_bx = Bx :: build ( self . cx , cleanup_llbb) ;
1604- funclet = cleanup_bx. cleanup_pad ( None , & [ ] ) ;
1605- cleanup_bx. br ( llbb) ;
1606- }
1607- }
1556+ let cleanup_bb = Bx :: append_block ( self . cx , self . llfn , & format ! ( "funclet_{:?}" , bb) ) ;
1557+ let mut cleanup_bx = Bx :: build ( self . cx , cleanup_bb) ;
1558+ let funclet = cleanup_bx. cleanup_pad ( None , & [ ] ) ;
1559+ cleanup_bx. br ( llbb) ;
16081560 self . funclets [ bb] = Some ( funclet) ;
1609- ret_llbb
1561+ cleanup_bb
16101562 } else {
16111563 let cleanup_llbb = Bx :: append_block ( self . cx , self . llfn , "cleanup" ) ;
16121564 let mut cleanup_bx = Bx :: build ( self . cx , cleanup_llbb) ;
@@ -1633,26 +1585,68 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16331585 } )
16341586 }
16351587
1636- fn double_unwind_guard ( & mut self ) -> Bx :: BasicBlock {
1637- self . double_unwind_guard . unwrap_or_else ( || {
1638- assert ! ( !base:: wants_msvc_seh( self . cx. sess( ) ) ) ;
1588+ fn terminate_block ( & mut self ) -> Bx :: BasicBlock {
1589+ self . terminate_block . unwrap_or_else ( || {
1590+ let funclet;
1591+ let llbb;
1592+ let mut bx;
1593+ if base:: wants_msvc_seh ( self . cx . sess ( ) ) {
1594+ // This is a basic block that we're aborting the program for,
1595+ // notably in an `extern` function. These basic blocks are inserted
1596+ // so that we assert that `extern` functions do indeed not panic,
1597+ // and if they do we abort the process.
1598+ //
1599+ // On MSVC these are tricky though (where we're doing funclets). If
1600+ // we were to do a cleanuppad (like below) the normal functions like
1601+ // `longjmp` would trigger the abort logic, terminating the
1602+ // program. Instead we insert the equivalent of `catch(...)` for C++
1603+ // which magically doesn't trigger when `longjmp` files over this
1604+ // frame.
1605+ //
1606+ // Lots more discussion can be found on #48251 but this codegen is
1607+ // modeled after clang's for:
1608+ //
1609+ // try {
1610+ // foo();
1611+ // } catch (...) {
1612+ // bar();
1613+ // }
1614+ llbb = Bx :: append_block ( self . cx , self . llfn , "cs_terminate" ) ;
1615+ let cp_llbb = Bx :: append_block ( self . cx , self . llfn , "cp_terminate" ) ;
1616+
1617+ let mut cs_bx = Bx :: build ( self . cx , llbb) ;
1618+ let cs = cs_bx. catch_switch ( None , None , & [ llbb] ) ;
1619+
1620+ // The "null" here is actually a RTTI type descriptor for the
1621+ // C++ personality function, but `catch (...)` has no type so
1622+ // it's null. The 64 here is actually a bitfield which
1623+ // represents that this is a catch-all block.
1624+ bx = Bx :: build ( self . cx , cp_llbb) ;
1625+ let null =
1626+ bx. const_null ( bx. type_i8p_ext ( bx. cx ( ) . data_layout ( ) . instruction_address_space ) ) ;
1627+ let sixty_four = bx. const_i32 ( 64 ) ;
1628+ funclet = Some ( bx. catch_pad ( cs, & [ null, sixty_four, null] ) ) ;
1629+ } else {
1630+ llbb = Bx :: append_block ( self . cx , self . llfn , "terminate" ) ;
1631+ bx = Bx :: build ( self . cx , llbb) ;
1632+
1633+ let llpersonality = self . cx . eh_personality ( ) ;
1634+ bx. cleanup_landing_pad ( llpersonality) ;
16391635
1640- let llbb = Bx :: append_block ( self . cx , self . llfn , "abort" ) ;
1641- let mut bx = Bx :: build ( self . cx , llbb) ;
1642- self . set_debug_loc ( & mut bx, mir:: SourceInfo :: outermost ( self . mir . span ) ) ;
1636+ funclet = None ;
1637+ }
16431638
1644- let llpersonality = self . cx . eh_personality ( ) ;
1645- bx. cleanup_landing_pad ( llpersonality) ;
1639+ self . set_debug_loc ( & mut bx, mir:: SourceInfo :: outermost ( self . mir . span ) ) ;
16461640
16471641 let ( fn_abi, fn_ptr) = common:: build_langcall ( & bx, None , LangItem :: PanicCannotUnwind ) ;
16481642 let fn_ty = bx. fn_decl_backend_type ( & fn_abi) ;
16491643
1650- let llret = bx. call ( fn_ty, Some ( & fn_abi) , fn_ptr, & [ ] , None ) ;
1644+ let llret = bx. call ( fn_ty, Some ( & fn_abi) , fn_ptr, & [ ] , funclet . as_ref ( ) ) ;
16511645 bx. do_not_inline ( llret) ;
16521646
16531647 bx. unreachable ( ) ;
16541648
1655- self . double_unwind_guard = Some ( llbb) ;
1649+ self . terminate_block = Some ( llbb) ;
16561650 llbb
16571651 } )
16581652 }
0 commit comments