@@ -170,22 +170,17 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
170
170
171
171
let unwind_block = match unwind {
172
172
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
- }
187
173
mir:: UnwindAction :: Continue => None ,
188
174
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
+ }
189
184
} ;
190
185
191
186
if let Some ( unwind_block) = unwind_block {
@@ -253,7 +248,14 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
253
248
instance : Instance < ' _ > ,
254
249
mergeable_succ : bool ,
255
250
) -> 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 {
257
259
let ret_llbb = if let Some ( target) = destination {
258
260
fx. llbb ( target)
259
261
} else {
@@ -266,7 +268,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
266
268
options,
267
269
line_spans,
268
270
instance,
269
- Some ( ( ret_llbb, self . llbb_with_cleanup ( fx , cleanup) , self . funclet ( fx) ) ) ,
271
+ Some ( ( ret_llbb, cleanup, self . funclet ( fx) ) ) ,
270
272
) ;
271
273
MergingSucc :: False
272
274
} else {
@@ -1551,62 +1553,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1551
1553
fn landing_pad_for_uncached ( & mut self , bb : mir:: BasicBlock ) -> Bx :: BasicBlock {
1552
1554
let llbb = self . llbb ( bb) ;
1553
1555
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) ;
1608
1560
self . funclets [ bb] = Some ( funclet) ;
1609
- ret_llbb
1561
+ cleanup_bb
1610
1562
} else {
1611
1563
let cleanup_llbb = Bx :: append_block ( self . cx , self . llfn , "cleanup" ) ;
1612
1564
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> {
1633
1585
} )
1634
1586
}
1635
1587
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) ;
1639
1635
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
+ }
1643
1638
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 ) ) ;
1646
1640
1647
1641
let ( fn_abi, fn_ptr) = common:: build_langcall ( & bx, None , LangItem :: PanicCannotUnwind ) ;
1648
1642
let fn_ty = bx. fn_decl_backend_type ( & fn_abi) ;
1649
1643
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 ( ) ) ;
1651
1645
bx. do_not_inline ( llret) ;
1652
1646
1653
1647
bx. unreachable ( ) ;
1654
1648
1655
- self . double_unwind_guard = Some ( llbb) ;
1649
+ self . terminate_block = Some ( llbb) ;
1656
1650
llbb
1657
1651
} )
1658
1652
}
0 commit comments