8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use llvm:: { BasicBlockRef , ValueRef } ;
11
+ use llvm:: { BasicBlockRef , ValueRef , OperandBundleDef } ;
12
12
use rustc:: middle:: ty;
13
13
use rustc:: mir:: repr as mir;
14
14
use syntax:: abi:: Abi ;
@@ -34,15 +34,40 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
34
34
let mut bcx = self . bcx ( bb) ;
35
35
let data = self . mir . basic_block_data ( bb) ;
36
36
37
+ // MSVC SEH bits
38
+ let ( cleanup_pad, cleanup_bundle) = if let Some ( ( cp, cb) ) = self . make_cleanup_pad ( bb) {
39
+ ( Some ( cp) , Some ( cb) )
40
+ } else {
41
+ ( None , None )
42
+ } ;
43
+ let funclet_br = |bcx : BlockAndBuilder , llbb : BasicBlockRef | if let Some ( cp) = cleanup_pad {
44
+ bcx. cleanup_ret ( cp, Some ( llbb) ) ;
45
+ } else {
46
+ bcx. br ( llbb) ;
47
+ } ;
48
+
37
49
for statement in & data. statements {
38
50
bcx = self . trans_statement ( bcx, statement) ;
39
51
}
40
52
41
53
debug ! ( "trans_block: terminator: {:?}" , data. terminator( ) ) ;
42
54
43
55
match * data. terminator ( ) {
56
+ mir:: Terminator :: Resume => {
57
+ if let Some ( cleanup_pad) = cleanup_pad {
58
+ bcx. cleanup_ret ( cleanup_pad, None ) ;
59
+ } else {
60
+ let ps = self . get_personality_slot ( & bcx) ;
61
+ let lp = bcx. load ( ps) ;
62
+ bcx. with_block ( |bcx| {
63
+ base:: call_lifetime_end ( bcx, ps) ;
64
+ base:: trans_unwind_resume ( bcx, lp) ;
65
+ } ) ;
66
+ }
67
+ }
68
+
44
69
mir:: Terminator :: Goto { target } => {
45
- bcx . br ( self . llblock ( target) ) ;
70
+ funclet_br ( bcx , self . llblock ( target) ) ;
46
71
}
47
72
48
73
mir:: Terminator :: If { ref cond, targets : ( true_bb, false_bb) } => {
@@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
85
110
}
86
111
}
87
112
88
- mir:: Terminator :: Resume => {
89
- let ps = self . get_personality_slot ( & bcx) ;
90
- let lp = bcx. load ( ps) ;
91
- bcx. with_block ( |bcx| {
92
- base:: call_lifetime_end ( bcx, ps) ;
93
- base:: trans_unwind_resume ( bcx, lp) ;
94
- } ) ;
95
- }
96
-
97
113
mir:: Terminator :: Return => {
98
114
let return_ty = bcx. monomorphize ( & self . mir . return_ty ) ;
99
115
bcx. with_block ( |bcx| {
100
- base:: build_return_block ( bcx . fcx , bcx, return_ty, DebugLoc :: None ) ;
116
+ base:: build_return_block ( self . fcx , bcx, return_ty, DebugLoc :: None ) ;
101
117
} )
102
118
}
103
119
@@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
106
122
let ty = lvalue. ty . to_ty ( bcx. tcx ( ) ) ;
107
123
// Double check for necessity to drop
108
124
if !glue:: type_needs_drop ( bcx. tcx ( ) , ty) {
109
- bcx . br ( self . llblock ( target) ) ;
125
+ funclet_br ( bcx , self . llblock ( target) ) ;
110
126
return ;
111
127
}
112
128
let drop_fn = glue:: get_drop_glue ( bcx. ccx ( ) , ty) ;
@@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
123
139
& [ llvalue] ,
124
140
self . llblock ( target) ,
125
141
unwind. llbb ( ) ,
126
- None ,
142
+ cleanup_bundle . as_ref ( ) ,
127
143
None ) ;
128
144
} else {
129
- bcx. call ( drop_fn, & [ llvalue] , None , None ) ;
130
- bcx . br ( self . llblock ( target) ) ;
145
+ bcx. call ( drop_fn, & [ llvalue] , cleanup_bundle . as_ref ( ) , None ) ;
146
+ funclet_br ( bcx , self . llblock ( target) ) ;
131
147
}
132
148
}
133
149
@@ -191,22 +207,22 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
191
207
& llargs[ ..] ,
192
208
unreachable_blk. llbb ,
193
209
landingpad. llbb ( ) ,
194
- None ,
210
+ cleanup_bundle . as_ref ( ) ,
195
211
Some ( attrs) ) ;
196
212
} ,
197
213
( false , & Some ( cleanup) , & Some ( ( _, success) ) ) => {
198
214
let cleanup = self . bcx ( cleanup) ;
199
215
let landingpad = self . make_landing_pad ( cleanup) ;
200
216
let ( target, postinvoke) = if must_copy_dest {
201
- ( bcx . fcx ( ) . new_block ( "" , None ) . build ( ) , Some ( self . bcx ( success) ) )
217
+ ( self . fcx . new_block ( "" , None ) . build ( ) , Some ( self . bcx ( success) ) )
202
218
} else {
203
219
( self . bcx ( success) , None )
204
220
} ;
205
221
let invokeret = bcx. invoke ( callee. immediate ( ) ,
206
222
& llargs[ ..] ,
207
223
target. llbb ( ) ,
208
224
landingpad. llbb ( ) ,
209
- None ,
225
+ cleanup_bundle . as_ref ( ) ,
210
226
Some ( attrs) ) ;
211
227
if let Some ( postinvoketarget) = postinvoke {
212
228
// We translate the copy into a temporary block. The temporary block is
@@ -242,13 +258,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
242
258
}
243
259
} ,
244
260
( false , _, & None ) => {
245
- bcx. call ( callee. immediate ( ) , & llargs[ ..] , None , Some ( attrs) ) ;
261
+ bcx. call ( callee. immediate ( ) ,
262
+ & llargs[ ..] ,
263
+ cleanup_bundle. as_ref ( ) ,
264
+ Some ( attrs) ) ;
246
265
bcx. unreachable ( ) ;
247
266
}
248
267
( false , _, & Some ( ( _, target) ) ) => {
249
268
let llret = bcx. call ( callee. immediate ( ) ,
250
269
& llargs[ ..] ,
251
- None ,
270
+ cleanup_bundle . as_ref ( ) ,
252
271
Some ( attrs) ) ;
253
272
if must_copy_dest {
254
273
let ( ret_dest, ret_ty) = ret_dest_ty
@@ -257,7 +276,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
257
276
base:: store_ty ( bcx, llret, ret_dest. llval , ret_ty) ;
258
277
} ) ;
259
278
}
260
- bcx . br ( self . llblock ( target) ) ;
279
+ funclet_br ( bcx , self . llblock ( target) ) ;
261
280
}
262
281
// Foreign functions
263
282
( true , _, destination) => {
@@ -273,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
273
292
debugloc)
274
293
} ) ;
275
294
if let Some ( ( _, target) ) = * destination {
276
- bcx . br ( self . llblock ( target) ) ;
295
+ funclet_br ( bcx , self . llblock ( target) ) ;
277
296
}
278
297
} ,
279
298
}
@@ -296,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
296
315
}
297
316
}
298
317
318
+ /// Create a landingpad wrapper around the given Block.
319
+ ///
320
+ /// No-op in MSVC SEH scheme.
299
321
fn make_landing_pad ( & mut self ,
300
322
cleanup : BlockAndBuilder < ' bcx , ' tcx > )
301
323
-> BlockAndBuilder < ' bcx , ' tcx >
302
324
{
303
- // FIXME(#30941) this doesn't handle msvc-style exceptions
325
+ if base:: wants_msvc_seh ( cleanup. sess ( ) ) {
326
+ return cleanup;
327
+ }
304
328
let bcx = self . fcx . new_block ( "cleanup" , None ) . build ( ) ;
305
329
let ccx = bcx. ccx ( ) ;
306
330
let llpersonality = self . fcx . eh_personality ( ) ;
@@ -313,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
313
337
bcx
314
338
}
315
339
340
+ /// Create prologue cleanuppad instruction under MSVC SEH handling scheme.
341
+ ///
342
+ /// Also handles setting some state for the original trans and creating an operand bundle for
343
+ /// function calls.
344
+ fn make_cleanup_pad ( & mut self , bb : mir:: BasicBlock ) -> Option < ( ValueRef , OperandBundleDef ) > {
345
+ let bcx = self . bcx ( bb) ;
346
+ let data = self . mir . basic_block_data ( bb) ;
347
+ let use_funclets = base:: wants_msvc_seh ( bcx. sess ( ) ) && data. is_cleanup ;
348
+ let cleanup_pad = if use_funclets {
349
+ bcx. set_personality_fn ( self . fcx . eh_personality ( ) ) ;
350
+ Some ( bcx. cleanup_pad ( None , & [ ] ) )
351
+ } else {
352
+ None
353
+ } ;
354
+ // Set the landingpad global-state for old translator, so it knows about the SEH used.
355
+ bcx. set_lpad ( if let Some ( cleanup_pad) = cleanup_pad {
356
+ Some ( common:: LandingPad :: msvc ( cleanup_pad) )
357
+ } else if data. is_cleanup {
358
+ Some ( common:: LandingPad :: gnu ( ) )
359
+ } else {
360
+ None
361
+ } ) ;
362
+ cleanup_pad. map ( |f| ( f, OperandBundleDef :: new ( "funclet" , & [ f] ) ) )
363
+ }
364
+
316
365
fn unreachable_block ( & mut self ) -> Block < ' bcx , ' tcx > {
317
366
self . unreachable_block . unwrap_or_else ( || {
318
367
let bl = self . fcx . new_block ( "unreachable" , None ) ;
0 commit comments