@@ -6,7 +6,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
6
6
use rustc_middle:: ty:: layout:: { FnAbiExt , HasTyCtxt , TyAndLayout } ;
7
7
use rustc_middle:: ty:: { self , Instance , Ty , TypeFoldable } ;
8
8
use rustc_target:: abi:: call:: { FnAbi , PassMode } ;
9
- use rustc_target:: abi:: HasDataLayout ;
9
+ use rustc_target:: abi:: { HasDataLayout , LayoutOf } ;
10
10
11
11
use std:: iter;
12
12
@@ -40,7 +40,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
40
40
/// value used for C++ unwinding, which must filter by type: we
41
41
/// don't really care about it very much. Anyway, this value
42
42
/// contains an alloca into which the personality is stored and
43
- /// then later loaded when generating the DIVERGE_BLOCK .
43
+ /// then later loaded when generating `resume` terminators .
44
44
personality_slot : Option < PlaceRef < ' tcx , Bx :: Value > > ,
45
45
46
46
/// A `Block` for each MIR `BasicBlock`
@@ -145,15 +145,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
145
145
146
146
let mut bx = Bx :: new_block ( cx, llfn, "start" ) ;
147
147
148
- if mir. basic_blocks ( ) . iter ( ) . any ( |bb| bb. is_cleanup ) {
148
+ let personality_slot = if mir. basic_blocks ( ) . iter ( ) . any ( |bb| bb. is_cleanup ) {
149
149
bx. set_personality_fn ( cx. eh_personality ( ) ) ;
150
- }
150
+
151
+ if base:: wants_msvc_seh ( bx. sess ( ) ) {
152
+ // MSVC doesn't use landing pads.
153
+ None
154
+ } else {
155
+ // FIXME(eddyb) the use of `PlaceRef` requires a Rust type, and taking apart
156
+ // (and later putting back together) the pair, instead of treating it opaquely.
157
+ let layout = cx. layout_of (
158
+ cx. tcx ( ) . intern_tup ( & [ cx. tcx ( ) . mk_mut_ptr ( cx. tcx ( ) . types . u8 ) , cx. tcx ( ) . types . i32 ] ) ,
159
+ ) ;
160
+ Some ( PlaceRef :: alloca ( & mut bx, layout) )
161
+ }
162
+ } else {
163
+ None
164
+ } ;
151
165
152
166
let cleanup_kinds = analyze:: cleanup_kinds ( & mir) ;
153
167
// Allocate a `Block` for every basic block, except
154
168
// the start block, if nothing loops back to it.
155
169
let reentrant_start_block = !mir. predecessors ( ) [ mir:: START_BLOCK ] . is_empty ( ) ;
156
- let block_bxs : IndexVec < mir:: BasicBlock , Bx :: BasicBlock > = mir
170
+ let block_llbbs : IndexVec < mir:: BasicBlock , Bx :: BasicBlock > = mir
157
171
. basic_blocks ( )
158
172
. indices ( )
159
173
. map ( |bb| {
@@ -165,15 +179,16 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
165
179
} )
166
180
. collect ( ) ;
167
181
168
- let ( landing_pads, funclets) = create_funclets ( & mir, & mut bx, & cleanup_kinds, & block_bxs) ;
182
+ let ( landing_pads, funclets) =
183
+ landing_pads_and_funclets ( & mir, & mut bx, & cleanup_kinds, & block_llbbs, personality_slot) ;
169
184
let mut fx = FunctionCx {
170
185
instance,
171
186
mir,
172
187
llfn,
173
188
fn_abi,
174
189
cx,
175
- personality_slot : None ,
176
- blocks : block_bxs ,
190
+ personality_slot,
191
+ blocks : block_llbbs ,
177
192
unreachable_block : None ,
178
193
cleanup_kinds,
179
194
landing_pads,
@@ -273,24 +288,51 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
273
288
}
274
289
}
275
290
276
- fn create_funclets < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
291
+ fn landing_pads_and_funclets < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
277
292
mir : & ' tcx mir:: Body < ' tcx > ,
278
293
bx : & mut Bx ,
279
294
cleanup_kinds : & IndexVec < mir:: BasicBlock , CleanupKind > ,
280
- block_bxs : & IndexVec < mir:: BasicBlock , Bx :: BasicBlock > ,
295
+ block_llbbs : & IndexVec < mir:: BasicBlock , Bx :: BasicBlock > ,
296
+ personality_slot : Option < PlaceRef < ' tcx , Bx :: Value > > ,
281
297
) -> (
282
298
IndexVec < mir:: BasicBlock , Option < Bx :: BasicBlock > > ,
283
299
IndexVec < mir:: BasicBlock , Option < Bx :: Funclet > > ,
284
300
) {
285
- iter:: zip ( block_bxs . iter_enumerated ( ) , cleanup_kinds)
301
+ iter:: zip ( block_llbbs . iter_enumerated ( ) , cleanup_kinds)
286
302
. map ( |( ( bb, & llbb) , cleanup_kind) | {
287
303
match * cleanup_kind {
288
- CleanupKind :: Funclet if base:: wants_msvc_seh ( bx. sess ( ) ) => { }
304
+ CleanupKind :: Funclet { .. } if base:: wants_msvc_seh ( bx. sess ( ) ) => {
305
+ // (cont'd below, outside the `match`)
306
+ }
307
+
308
+ // GNU requires a landing pad *only* when unwinding into
309
+ // cleanup blocks, not when branching between them.
310
+ CleanupKind :: Funclet { unwind_may_land_here : true } => {
311
+ let mut bx = bx. build_sibling_block ( "cleanup" ) ;
312
+ let pad_bb = bx. llbb ( ) ;
313
+
314
+ let llpersonality = bx. cx ( ) . eh_personality ( ) ;
315
+ let llretty = bx. cx ( ) . type_landing_pad ( ) ;
316
+ let lp = bx. landing_pad ( llretty, llpersonality, 1 ) ;
317
+ bx. set_cleanup ( lp) ;
318
+
319
+ // FIXME(eddyb) consider not using `PlaceRef` for `slot`, to avoid
320
+ // having to take apart (and later put back together) the pair.
321
+ let slot = personality_slot. unwrap ( ) ;
322
+ slot. storage_live ( & mut bx) ;
323
+ OperandValue :: Pair ( bx. extract_value ( lp, 0 ) , bx. extract_value ( lp, 1 ) )
324
+ . store ( & mut bx, slot) ;
325
+
326
+ bx. br ( llbb) ;
327
+
328
+ return ( Some ( pad_bb) , None ) ;
329
+ }
330
+
289
331
_ => return ( None , None ) ,
290
332
}
291
333
292
334
let funclet;
293
- let ret_llbb ;
335
+ let pad_llbb ;
294
336
match mir[ bb] . terminator . as_ref ( ) . map ( |t| & t. kind ) {
295
337
// This is a basic block that we're aborting the program for,
296
338
// notably in an `extern` function. These basic blocks are inserted
@@ -315,7 +357,7 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
315
357
Some ( & mir:: TerminatorKind :: Abort ) => {
316
358
let mut cs_bx = bx. build_sibling_block ( & format ! ( "cs_funclet{:?}" , bb) ) ;
317
359
let mut cp_bx = bx. build_sibling_block ( & format ! ( "cp_funclet{:?}" , bb) ) ;
318
- ret_llbb = cs_bx. llbb ( ) ;
360
+ pad_llbb = cs_bx. llbb ( ) ;
319
361
320
362
let cs = cs_bx. catch_switch ( None , None , 1 ) ;
321
363
cs_bx. add_handler ( cs, cp_bx. llbb ( ) ) ;
@@ -333,13 +375,13 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
333
375
}
334
376
_ => {
335
377
let mut cleanup_bx = bx. build_sibling_block ( & format ! ( "funclet_{:?}" , bb) ) ;
336
- ret_llbb = cleanup_bx. llbb ( ) ;
378
+ pad_llbb = cleanup_bx. llbb ( ) ;
337
379
funclet = cleanup_bx. cleanup_pad ( None , & [ ] ) ;
338
380
cleanup_bx. br ( llbb) ;
339
381
}
340
382
} ;
341
383
342
- ( Some ( ret_llbb ) , Some ( funclet) )
384
+ ( Some ( pad_llbb ) , Some ( funclet) )
343
385
} )
344
386
. unzip ( )
345
387
}
0 commit comments