@@ -12,7 +12,7 @@ use crate::MemFlags;
12
12
use rustc_ast as ast;
13
13
use rustc_ast:: { InlineAsmOptions , InlineAsmTemplatePiece } ;
14
14
use rustc_hir:: lang_items:: LangItem ;
15
- use rustc_middle:: mir:: { self , AssertKind , SwitchTargets } ;
15
+ use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
16
16
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
17
17
use rustc_middle:: ty:: print:: { with_no_trimmed_paths, with_no_visible_paths} ;
18
18
use rustc_middle:: ty:: { self , Instance , Ty } ;
@@ -178,7 +178,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
178
178
mir:: UnwindAction :: Cleanup ( cleanup) => Some ( self . llbb_with_cleanup ( fx, cleanup) ) ,
179
179
mir:: UnwindAction :: Continue => None ,
180
180
mir:: UnwindAction :: Unreachable => None ,
181
- mir:: UnwindAction :: Terminate => {
181
+ mir:: UnwindAction :: Terminate ( reason ) => {
182
182
if fx. mir [ self . bb ] . is_cleanup && base:: wants_new_eh_instructions ( fx. cx . tcx ( ) . sess ) {
183
183
// MSVC SEH will abort automatically if an exception tries to
184
184
// propagate out from cleanup.
@@ -191,7 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
191
191
192
192
None
193
193
} else {
194
- Some ( fx. terminate_block ( ) )
194
+ Some ( fx. terminate_block ( reason ) )
195
195
}
196
196
}
197
197
} ;
@@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264
264
) -> MergingSucc {
265
265
let unwind_target = match unwind {
266
266
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 ) ) ,
268
268
mir:: UnwindAction :: Continue => None ,
269
269
mir:: UnwindAction :: Unreachable => None ,
270
270
} ;
@@ -649,12 +649,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
649
649
helper : TerminatorCodegenHelper < ' tcx > ,
650
650
bx : & mut Bx ,
651
651
terminator : & mir:: Terminator < ' tcx > ,
652
+ reason : UnwindTerminateReason ,
652
653
) {
653
654
let span = terminator. source_info . span ;
654
655
self . set_debug_loc ( bx, terminator. source_info ) ;
655
656
656
657
// 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 ( ) ) ;
658
659
659
660
// Codegen the actual panic invoke/call.
660
661
let merging_succ = helper. do_call (
@@ -1229,8 +1230,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1229
1230
MergingSucc :: False
1230
1231
}
1231
1232
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 ) ;
1234
1235
MergingSucc :: False
1235
1236
}
1236
1237
@@ -1579,79 +1580,81 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1579
1580
} )
1580
1581
}
1581
1582
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
+ }
1635
1587
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) ;
1638
1639
1639
- funclet = None ;
1640
- }
1640
+ let llpersonality = self . cx . eh_personality ( ) ;
1641
+ bx. filter_landing_pad ( llpersonality) ;
1642
+
1643
+ funclet = None ;
1644
+ }
1641
1645
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 ) ) ;
1643
1647
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) ;
1646
1650
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) ;
1649
1653
1650
- bx. unreachable ( ) ;
1654
+ bx. unreachable ( ) ;
1651
1655
1652
- self . terminate_block = Some ( llbb) ;
1653
- llbb
1654
- } )
1656
+ self . terminate_block = Some ( ( llbb, reason) ) ;
1657
+ llbb
1655
1658
}
1656
1659
1657
1660
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already
0 commit comments