1
1
use crate :: transform:: MirPass ;
2
+ use rustc_hir:: def:: DefKind ;
2
3
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
3
4
use rustc_middle:: mir:: * ;
4
5
use rustc_middle:: ty:: layout;
@@ -24,15 +25,28 @@ pub struct AbortUnwindingCalls;
24
25
25
26
impl < ' tcx > MirPass < ' tcx > for AbortUnwindingCalls {
26
27
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
+
27
41
// This pass only runs on functions which themselves cannot unwind,
28
42
// forcibly changing the body of the function to structurally provide
29
43
// this guarantee by aborting on an unwind. If this function can unwind,
30
44
// then there's nothing to do because it already should work correctly.
31
45
//
32
46
// Here we test for this function itself whether its ABI allows
33
47
// 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) ;
36
50
let body_abi = match body_ty. kind ( ) {
37
51
ty:: FnDef ( ..) => body_ty. fn_sig ( tcx) . abi ( ) ,
38
52
ty:: Closure ( ..) => Abi :: RustCall ,
@@ -51,22 +65,31 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
51
65
if block. is_cleanup {
52
66
continue ;
53
67
}
68
+ let terminator = match & block. terminator {
69
+ Some ( terminator) => terminator,
70
+ None => continue ,
71
+ } ;
72
+ let span = terminator. source_info . span ;
54
73
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 )
58
90
}
59
91
_ => continue ,
60
92
} ;
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 ( ) ) ;
70
93
71
94
// If this function call can't unwind, then there's no need for it
72
95
// to have a landing pad. This means that we can remove any cleanup
@@ -102,23 +125,28 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
102
125
let abort_bb = body. basic_blocks_mut ( ) . push ( bb) ;
103
126
104
127
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 ( ) ) ;
109
129
* cleanup = Some ( abort_bb) ;
110
130
}
111
131
}
112
132
113
133
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 ( ) ) ;
118
135
* cleanup = None ;
119
136
}
120
137
121
138
// We may have invalidated some `cleanup` blocks so clean those up now.
122
139
super :: simplify:: remove_dead_blocks ( tcx, body) ;
123
140
}
124
141
}
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