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
@@ -180,34 +196,33 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
180
196
}
181
197
}
182
198
183
- let avoid_invoke = bcx. with_block ( |bcx| base:: avoid_invoke ( bcx) ) ;
184
199
// Many different ways to call a function handled here
185
- match ( is_foreign, avoid_invoke , cleanup, destination) {
200
+ match ( is_foreign, cleanup, destination) {
186
201
// The two cases below are the only ones to use LLVM’s `invoke`.
187
- ( false , false , & Some ( cleanup) , & None ) => {
202
+ ( false , & Some ( cleanup) , & None ) => {
188
203
let cleanup = self . bcx ( cleanup) ;
189
204
let landingpad = self . make_landing_pad ( cleanup) ;
190
205
let unreachable_blk = self . unreachable_block ( ) ;
191
206
bcx. invoke ( callee. immediate ( ) ,
192
207
& llargs[ ..] ,
193
208
unreachable_blk. llbb ,
194
209
landingpad. llbb ( ) ,
195
- None ,
210
+ cleanup_bundle . as_ref ( ) ,
196
211
Some ( attrs) ) ;
197
212
} ,
198
- ( false , false , & Some ( cleanup) , & Some ( ( _, success) ) ) => {
213
+ ( false , & Some ( cleanup) , & Some ( ( _, success) ) ) => {
199
214
let cleanup = self . bcx ( cleanup) ;
200
215
let landingpad = self . make_landing_pad ( cleanup) ;
201
216
let ( target, postinvoke) = if must_copy_dest {
202
- ( bcx . fcx ( ) . new_block ( "" , None ) . build ( ) , Some ( self . bcx ( success) ) )
217
+ ( self . fcx . new_block ( "" , None ) . build ( ) , Some ( self . bcx ( success) ) )
203
218
} else {
204
219
( self . bcx ( success) , None )
205
220
} ;
206
221
let invokeret = bcx. invoke ( callee. immediate ( ) ,
207
222
& llargs[ ..] ,
208
223
target. llbb ( ) ,
209
224
landingpad. llbb ( ) ,
210
- None ,
225
+ cleanup_bundle . as_ref ( ) ,
211
226
Some ( attrs) ) ;
212
227
if let Some ( postinvoketarget) = postinvoke {
213
228
// We translate the copy into a temporary block. The temporary block is
@@ -242,14 +257,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
242
257
target. br ( postinvoketarget. llbb ( ) ) ;
243
258
}
244
259
} ,
245
- ( false , _, _, & None ) => {
246
- bcx. call ( callee. immediate ( ) , & llargs[ ..] , None , Some ( attrs) ) ;
260
+ ( false , _, & None ) => {
261
+ bcx. call ( callee. immediate ( ) ,
262
+ & llargs[ ..] ,
263
+ cleanup_bundle. as_ref ( ) ,
264
+ Some ( attrs) ) ;
247
265
bcx. unreachable ( ) ;
248
266
}
249
- ( false , _, _ , & Some ( ( _, target) ) ) => {
267
+ ( false , _, & Some ( ( _, target) ) ) => {
250
268
let llret = bcx. call ( callee. immediate ( ) ,
251
269
& llargs[ ..] ,
252
- None ,
270
+ cleanup_bundle . as_ref ( ) ,
253
271
Some ( attrs) ) ;
254
272
if must_copy_dest {
255
273
let ( ret_dest, ret_ty) = ret_dest_ty
@@ -258,10 +276,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
258
276
base:: store_ty ( bcx, llret, ret_dest. llval , ret_ty) ;
259
277
} ) ;
260
278
}
261
- bcx . br ( self . llblock ( target) ) ;
279
+ funclet_br ( bcx , self . llblock ( target) ) ;
262
280
}
263
281
// Foreign functions
264
- ( true , _, _ , destination) => {
282
+ ( true , _, destination) => {
265
283
let ( dest, _) = ret_dest_ty
266
284
. expect ( "return destination is not set" ) ;
267
285
bcx = bcx. map_block ( |bcx| {
@@ -274,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
274
292
debugloc)
275
293
} ) ;
276
294
if let Some ( ( _, target) ) = * destination {
277
- bcx . br ( self . llblock ( target) ) ;
295
+ funclet_br ( bcx , self . llblock ( target) ) ;
278
296
}
279
297
} ,
280
298
}
@@ -297,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
297
315
}
298
316
}
299
317
318
+ /// Create a landingpad wrapper around the given Block.
319
+ ///
320
+ /// No-op in MSVC SEH scheme.
300
321
fn make_landing_pad ( & mut self ,
301
322
cleanup : BlockAndBuilder < ' bcx , ' tcx > )
302
323
-> BlockAndBuilder < ' bcx , ' tcx >
303
324
{
304
- // FIXME(#30941) this doesn't handle msvc-style exceptions
325
+ if base:: wants_msvc_seh ( cleanup. sess ( ) ) {
326
+ return cleanup;
327
+ }
305
328
let bcx = self . fcx . new_block ( "cleanup" , None ) . build ( ) ;
306
329
let ccx = bcx. ccx ( ) ;
307
330
let llpersonality = self . fcx . eh_personality ( ) ;
@@ -314,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
314
337
bcx
315
338
}
316
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
+
317
365
fn unreachable_block ( & mut self ) -> Block < ' bcx , ' tcx > {
318
366
self . unreachable_block . unwrap_or_else ( || {
319
367
let bl = self . fcx . new_block ( "unreachable" , None ) ;
0 commit comments