11use crate :: transform:: MirPass ;
2+ use rustc_hir:: def:: DefKind ;
23use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
34use rustc_middle:: mir:: * ;
45use rustc_middle:: ty:: layout;
@@ -24,15 +25,28 @@ pub struct AbortUnwindingCalls;
2425
2526impl < ' tcx > MirPass < ' tcx > for AbortUnwindingCalls {
2627 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
28+ let def_id = body. source . def_id ( ) ;
29+ let kind = tcx. def_kind ( def_id) ;
30+
31+ // We don't simplify the MIR of constants at this time because that
32+ // namely results in a cyclic query when we call `tcx.type_of` below.
33+ let is_function = match kind {
34+ DefKind :: Fn | DefKind :: AssocFn | DefKind :: Ctor ( ..) => true ,
35+ _ => tcx. is_closure ( def_id) ,
36+ } ;
37+ if !is_function {
38+ return ;
39+ }
40+
2741 // This pass only runs on functions which themselves cannot unwind,
2842 // forcibly changing the body of the function to structurally provide
2943 // this guarantee by aborting on an unwind. If this function can unwind,
3044 // then there's nothing to do because it already should work correctly.
3145 //
3246 // Here we test for this function itself whether its ABI allows
3347 // unwinding or not.
34- let body_flags = tcx. codegen_fn_attrs ( body . source . def_id ( ) ) . flags ;
35- let body_ty = tcx. type_of ( body . source . def_id ( ) ) ;
48+ let body_flags = tcx. codegen_fn_attrs ( def_id) . flags ;
49+ let body_ty = tcx. type_of ( def_id) ;
3650 let body_abi = match body_ty. kind ( ) {
3751 ty:: FnDef ( ..) => body_ty. fn_sig ( tcx) . abi ( ) ,
3852 ty:: Closure ( ..) => Abi :: RustCall ,
@@ -51,22 +65,31 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
5165 if block. is_cleanup {
5266 continue ;
5367 }
68+ let terminator = match & block. terminator {
69+ Some ( terminator) => terminator,
70+ None => continue ,
71+ } ;
72+ let span = terminator. source_info . span ;
5473
55- let ( func, source_info) = match & block. terminator {
56- Some ( Terminator { kind : TerminatorKind :: Call { func, .. } , source_info } ) => {
57- ( func, source_info)
74+ let call_can_unwind = match & terminator. kind {
75+ TerminatorKind :: Call { func, .. } => {
76+ let ty = func. ty ( body, tcx) ;
77+ let sig = ty. fn_sig ( tcx) ;
78+ let flags = match ty. kind ( ) {
79+ ty:: FnPtr ( _) => CodegenFnAttrFlags :: empty ( ) ,
80+ ty:: FnDef ( def_id, _) => tcx. codegen_fn_attrs ( * def_id) . flags ,
81+ _ => span_bug ! ( span, "invalid callee of type {:?}" , ty) ,
82+ } ;
83+ layout:: fn_can_unwind ( tcx, flags, sig. abi ( ) )
84+ }
85+ TerminatorKind :: Drop { .. }
86+ | TerminatorKind :: DropAndReplace { .. }
87+ | TerminatorKind :: Assert { .. }
88+ | TerminatorKind :: FalseUnwind { .. } => {
89+ layout:: fn_can_unwind ( tcx, CodegenFnAttrFlags :: empty ( ) , Abi :: Rust )
5890 }
5991 _ => continue ,
6092 } ;
61- let ty = func. ty ( body, tcx) ;
62- let sig = ty. fn_sig ( tcx) ;
63- let flags = match ty. kind ( ) {
64- ty:: FnPtr ( _) => CodegenFnAttrFlags :: empty ( ) ,
65- ty:: FnDef ( def_id, _) => tcx. codegen_fn_attrs ( * def_id) . flags ,
66- _ => span_bug ! ( source_info. span, "invalid callee of type {:?}" , ty) ,
67- } ;
68-
69- let call_can_unwind = layout:: fn_can_unwind ( tcx, flags, sig. abi ( ) ) ;
7093
7194 // If this function call can't unwind, then there's no need for it
7295 // to have a landing pad. This means that we can remove any cleanup
@@ -102,23 +125,28 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
102125 let abort_bb = body. basic_blocks_mut ( ) . push ( bb) ;
103126
104127 for bb in calls_to_terminate {
105- let cleanup = match & mut body. basic_blocks_mut ( ) [ bb] . terminator {
106- Some ( Terminator { kind : TerminatorKind :: Call { cleanup, .. } , .. } ) => cleanup,
107- _ => unreachable ! ( ) ,
108- } ;
128+ let cleanup = get_cleanup ( body. basic_blocks_mut ( ) [ bb] . terminator_mut ( ) ) ;
109129 * cleanup = Some ( abort_bb) ;
110130 }
111131 }
112132
113133 for id in cleanups_to_remove {
114- let cleanup = match & mut body. basic_blocks_mut ( ) [ id] . terminator {
115- Some ( Terminator { kind : TerminatorKind :: Call { cleanup, .. } , .. } ) => cleanup,
116- _ => unreachable ! ( ) ,
117- } ;
134+ let cleanup = get_cleanup ( body. basic_blocks_mut ( ) [ id] . terminator_mut ( ) ) ;
118135 * cleanup = None ;
119136 }
120137
121138 // We may have invalidated some `cleanup` blocks so clean those up now.
122139 super :: simplify:: remove_dead_blocks ( tcx, body) ;
123140 }
124141}
142+
143+ fn get_cleanup < ' a > ( t : & ' a mut Terminator < ' _ > ) -> & ' a mut Option < BasicBlock > {
144+ match & mut t. kind {
145+ TerminatorKind :: Call { cleanup, .. }
146+ | TerminatorKind :: Drop { unwind : cleanup, .. }
147+ | TerminatorKind :: DropAndReplace { unwind : cleanup, .. }
148+ | TerminatorKind :: Assert { cleanup, .. }
149+ | TerminatorKind :: FalseUnwind { unwind : cleanup, .. } => cleanup,
150+ _ => unreachable ! ( ) ,
151+ }
152+ }
0 commit comments