@@ -26,7 +26,11 @@ pub struct MirPatch<'tcx> {
26
26
pub new_blocks : Vec < BasicBlockData < ' tcx > > ,
27
27
pub new_statements : Vec < ( Location , StatementKind < ' tcx > ) > ,
28
28
pub new_locals : Vec < LocalDecl < ' tcx > > ,
29
- pub resume_block : BasicBlock ,
29
+ pub resume_block : Option < BasicBlock > ,
30
+ // Only for unreachable in cleanup path.
31
+ pub unreachable_cleanup_block : Option < BasicBlock > ,
32
+ pub terminate_block : Option < BasicBlock > ,
33
+ pub body_span : Span ,
30
34
pub next_local : usize ,
31
35
}
32
36
@@ -38,51 +42,87 @@ impl<'tcx> MirPatch<'tcx> {
38
42
new_statements : vec ! [ ] ,
39
43
new_locals : vec ! [ ] ,
40
44
next_local : body. local_decls . len ( ) ,
41
- resume_block : START_BLOCK ,
45
+ resume_block : None ,
46
+ unreachable_cleanup_block : None ,
47
+ terminate_block : None ,
48
+ body_span : body. span ,
42
49
} ;
43
50
44
- // make sure the MIR we create has a resume block. It is
45
- // completely legal to convert jumps to the resume block
46
- // to jumps to None, but we occasionally have to add
47
- // instructions just before that.
48
-
49
- let mut resume_block = None ;
50
- let mut resume_stmt_block = None ;
51
51
for ( bb, block) in body. basic_blocks . iter_enumerated ( ) {
52
- if let TerminatorKind :: Resume = block. terminator ( ) . kind {
53
- if !block. statements . is_empty ( ) {
54
- assert ! ( resume_stmt_block. is_none( ) ) ;
55
- resume_stmt_block = Some ( bb) ;
56
- } else {
57
- resume_block = Some ( bb) ;
58
- }
59
- break ;
52
+ // Check if we already have a resume block
53
+ if let TerminatorKind :: Resume = block. terminator ( ) . kind && block. statements . is_empty ( ) {
54
+ result. resume_block = Some ( bb) ;
55
+ continue ;
56
+ }
57
+
58
+ // Check if we already have an unreachable block
59
+ if let TerminatorKind :: Unreachable = block. terminator ( ) . kind
60
+ && block. statements . is_empty ( )
61
+ && block. is_cleanup
62
+ {
63
+ result. unreachable_cleanup_block = Some ( bb) ;
64
+ continue ;
60
65
}
66
+
67
+ // Check if we already have a terminate block
68
+ if let TerminatorKind :: Terminate = block. terminator ( ) . kind && block. statements . is_empty ( ) {
69
+ result. terminate_block = Some ( bb) ;
70
+ continue ;
71
+ }
72
+ }
73
+
74
+ result
75
+ }
76
+
77
+ pub fn resume_block ( & mut self ) -> BasicBlock {
78
+ if let Some ( bb) = self . resume_block {
79
+ return bb;
61
80
}
62
- let resume_block = resume_block. unwrap_or_else ( || {
63
- result. new_block ( BasicBlockData {
64
- statements : vec ! [ ] ,
65
- terminator : Some ( Terminator {
66
- source_info : SourceInfo :: outermost ( body. span ) ,
67
- kind : TerminatorKind :: Resume ,
68
- } ) ,
69
- is_cleanup : true ,
70
- } )
81
+
82
+ let bb = self . new_block ( BasicBlockData {
83
+ statements : vec ! [ ] ,
84
+ terminator : Some ( Terminator {
85
+ source_info : SourceInfo :: outermost ( self . body_span ) ,
86
+ kind : TerminatorKind :: Resume ,
87
+ } ) ,
88
+ is_cleanup : true ,
71
89
} ) ;
72
- result. resume_block = resume_block;
73
- if let Some ( resume_stmt_block) = resume_stmt_block {
74
- result. patch_terminator (
75
- resume_stmt_block,
76
- TerminatorKind :: Goto {
77
- target : resume_block,
78
- } ,
79
- ) ;
90
+ self . resume_block = Some ( bb) ;
91
+ bb
92
+ }
93
+
94
+ pub fn unreachable_cleanup_block ( & mut self ) -> BasicBlock {
95
+ if let Some ( bb) = self . unreachable_cleanup_block {
96
+ return bb;
80
97
}
81
- result
98
+
99
+ let bb = self . new_block ( BasicBlockData {
100
+ statements : vec ! [ ] ,
101
+ terminator : Some ( Terminator {
102
+ source_info : SourceInfo :: outermost ( self . body_span ) ,
103
+ kind : TerminatorKind :: Unreachable ,
104
+ } ) ,
105
+ is_cleanup : true ,
106
+ } ) ;
107
+ self . unreachable_cleanup_block = Some ( bb) ;
108
+ bb
82
109
}
83
110
84
- pub fn resume_block ( & self ) -> BasicBlock {
85
- self . resume_block
111
+ pub fn terminate_block ( & mut self ) -> BasicBlock {
112
+ if let Some ( bb) = self . terminate_block {
113
+ return bb;
114
+ }
115
+
116
+ let bb = self . new_block ( BasicBlockData {
117
+ statements : vec ! [ ] ,
118
+ terminator : Some ( Terminator {
119
+ source_info : SourceInfo :: outermost ( self . body_span ) ,
120
+ kind : TerminatorKind :: Terminate ,
121
+ } ) ,
122
+ is_cleanup : true ,
123
+ } ) ;
124
+ self . terminate_block = Some ( bb) ;
125
+ bb
86
126
}
87
127
88
128
pub fn is_patched ( & self , bb : BasicBlock ) -> bool {
@@ -94,10 +134,21 @@ impl<'tcx> MirPatch<'tcx> {
94
134
Some ( index) => self . new_blocks [ index] . statements . len ( ) ,
95
135
None => body[ bb] . statements . len ( ) ,
96
136
} ;
97
- Location {
98
- block : bb,
99
- statement_index : offset,
100
- }
137
+ Location { block : bb, statement_index : offset }
138
+ }
139
+
140
+ pub fn new_internal_with_info (
141
+ & mut self ,
142
+ ty : Ty < ' tcx > ,
143
+ span : Span ,
144
+ local_info : LocalInfo < ' tcx > ,
145
+ ) -> Local {
146
+ let index = self . next_local ;
147
+ self . next_local += 1 ;
148
+ let mut new_decl = LocalDecl :: new ( ty, span) . internal ( ) ;
149
+ * * new_decl. local_info . as_mut ( ) . assert_crate_local ( ) = local_info;
150
+ self . new_locals . push ( new_decl) ;
151
+ Local :: new ( index)
101
152
}
102
153
103
154
pub fn new_temp ( & mut self , ty : Ty < ' tcx > , span : Span ) -> Local {
@@ -114,7 +165,6 @@ impl<'tcx> MirPatch<'tcx> {
114
165
Local :: new ( index)
115
166
}
116
167
117
- #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
118
168
pub fn new_block ( & mut self , data : BasicBlockData < ' tcx > ) -> BasicBlock {
119
169
let block = BasicBlock :: new ( self . patch_map . len ( ) ) ;
120
170
debug ! ( "MirPatch: new_block: {:?}: {:?}" , block, data) ;
@@ -123,22 +173,21 @@ impl<'tcx> MirPatch<'tcx> {
123
173
block
124
174
}
125
175
126
- #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
127
176
pub fn patch_terminator ( & mut self , block : BasicBlock , new : TerminatorKind < ' tcx > ) {
128
177
assert ! ( self . patch_map[ block] . is_none( ) ) ;
178
+ debug ! ( "MirPatch: patch_terminator({:?}, {:?})" , block, new) ;
129
179
self . patch_map [ block] = Some ( new) ;
130
180
}
131
181
132
- #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
133
182
pub fn add_statement ( & mut self , loc : Location , stmt : StatementKind < ' tcx > ) {
183
+ debug ! ( "MirPatch: add_statement({:?}, {:?})" , loc, stmt) ;
134
184
self . new_statements . push ( ( loc, stmt) ) ;
135
185
}
136
186
137
187
pub fn add_assign ( & mut self , loc : Location , place : Place < ' tcx > , rv : Rvalue < ' tcx > ) {
138
188
self . add_statement ( loc, StatementKind :: Assign ( Box :: new ( ( place, rv) ) ) ) ;
139
189
}
140
190
141
- #[ tracing:: instrument( level = "debug" , skip_all) ]
142
191
pub fn apply ( self , body : & mut Body < ' tcx > ) {
143
192
debug ! (
144
193
"MirPatch: {:?} new temps, starting from index {}: {:?}" ,
@@ -151,12 +200,17 @@ impl<'tcx> MirPatch<'tcx> {
151
200
self . new_blocks. len( ) ,
152
201
body. basic_blocks. len( )
153
202
) ;
154
- body. basic_blocks_mut ( ) . extend ( self . new_blocks ) ;
203
+ let bbs = if self . patch_map . is_empty ( ) && self . new_blocks . is_empty ( ) {
204
+ body. basic_blocks . as_mut_preserves_cfg ( )
205
+ } else {
206
+ body. basic_blocks . as_mut ( )
207
+ } ;
208
+ bbs. extend ( self . new_blocks ) ;
155
209
body. local_decls . extend ( self . new_locals ) ;
156
210
for ( src, patch) in self . patch_map . into_iter_enumerated ( ) {
157
211
if let Some ( patch) = patch {
158
212
debug ! ( "MirPatch: patching block {:?}" , src) ;
159
- body [ src] . terminator_mut ( ) . kind = patch;
213
+ bbs [ src] . terminator_mut ( ) . kind = patch;
160
214
}
161
215
}
162
216
@@ -170,19 +224,12 @@ impl<'tcx> MirPatch<'tcx> {
170
224
delta = 0 ;
171
225
last_bb = loc. block ;
172
226
}
173
- debug ! (
174
- "MirPatch: adding statement {:?} at loc {:?}+{}" ,
175
- stmt, loc, delta
176
- ) ;
227
+ debug ! ( "MirPatch: adding statement {:?} at loc {:?}+{}" , stmt, loc, delta) ;
177
228
loc. statement_index += delta;
178
229
let source_info = Self :: source_info_for_index ( & body[ loc. block ] , loc) ;
179
- body[ loc. block ] . statements . insert (
180
- loc. statement_index ,
181
- Statement {
182
- source_info,
183
- kind : stmt,
184
- } ,
185
- ) ;
230
+ body[ loc. block ]
231
+ . statements
232
+ . insert ( loc. statement_index , Statement { source_info, kind : stmt } ) ;
186
233
delta += 1 ;
187
234
}
188
235
}
@@ -201,4 +248,4 @@ impl<'tcx> MirPatch<'tcx> {
201
248
} ;
202
249
Self :: source_info_for_index ( data, loc)
203
250
}
204
- }
251
+ }
0 commit comments