88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use llvm:: { BasicBlockRef , ValueRef } ;
11+ use llvm:: { BasicBlockRef , ValueRef , OperandBundleDef } ;
1212use rustc:: middle:: ty;
1313use rustc:: mir:: repr as mir;
1414use syntax:: abi:: Abi ;
@@ -34,15 +34,40 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
3434 let mut bcx = self . bcx ( bb) ;
3535 let data = self . mir . basic_block_data ( bb) ;
3636
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+
3749 for statement in & data. statements {
3850 bcx = self . trans_statement ( bcx, statement) ;
3951 }
4052
4153 debug ! ( "trans_block: terminator: {:?}" , data. terminator( ) ) ;
4254
4355 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+
4469 mir:: Terminator :: Goto { target } => {
45- bcx . br ( self . llblock ( target) ) ;
70+ funclet_br ( bcx , self . llblock ( target) ) ;
4671 }
4772
4873 mir:: Terminator :: If { ref cond, targets : ( true_bb, false_bb) } => {
@@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
85110 }
86111 }
87112
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-
97113 mir:: Terminator :: Return => {
98114 let return_ty = bcx. monomorphize ( & self . mir . return_ty ) ;
99115 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 ) ;
101117 } )
102118 }
103119
@@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
106122 let ty = lvalue. ty . to_ty ( bcx. tcx ( ) ) ;
107123 // Double check for necessity to drop
108124 if !glue:: type_needs_drop ( bcx. tcx ( ) , ty) {
109- bcx . br ( self . llblock ( target) ) ;
125+ funclet_br ( bcx , self . llblock ( target) ) ;
110126 return ;
111127 }
112128 let drop_fn = glue:: get_drop_glue ( bcx. ccx ( ) , ty) ;
@@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
123139 & [ llvalue] ,
124140 self . llblock ( target) ,
125141 unwind. llbb ( ) ,
126- None ,
142+ cleanup_bundle . as_ref ( ) ,
127143 None ) ;
128144 } 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) ) ;
131147 }
132148 }
133149
@@ -180,34 +196,33 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
180196 }
181197 }
182198
183- let avoid_invoke = bcx. with_block ( |bcx| base:: avoid_invoke ( bcx) ) ;
184199 // Many different ways to call a function handled here
185- match ( is_foreign, avoid_invoke , cleanup, destination) {
200+ match ( is_foreign, cleanup, destination) {
186201 // The two cases below are the only ones to use LLVM’s `invoke`.
187- ( false , false , & Some ( cleanup) , & None ) => {
202+ ( false , & Some ( cleanup) , & None ) => {
188203 let cleanup = self . bcx ( cleanup) ;
189204 let landingpad = self . make_landing_pad ( cleanup) ;
190205 let unreachable_blk = self . unreachable_block ( ) ;
191206 bcx. invoke ( callee. immediate ( ) ,
192207 & llargs[ ..] ,
193208 unreachable_blk. llbb ,
194209 landingpad. llbb ( ) ,
195- None ,
210+ cleanup_bundle . as_ref ( ) ,
196211 Some ( attrs) ) ;
197212 } ,
198- ( false , false , & Some ( cleanup) , & Some ( ( _, success) ) ) => {
213+ ( false , & Some ( cleanup) , & Some ( ( _, success) ) ) => {
199214 let cleanup = self . bcx ( cleanup) ;
200215 let landingpad = self . make_landing_pad ( cleanup) ;
201216 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) ) )
203218 } else {
204219 ( self . bcx ( success) , None )
205220 } ;
206221 let invokeret = bcx. invoke ( callee. immediate ( ) ,
207222 & llargs[ ..] ,
208223 target. llbb ( ) ,
209224 landingpad. llbb ( ) ,
210- None ,
225+ cleanup_bundle . as_ref ( ) ,
211226 Some ( attrs) ) ;
212227 if let Some ( postinvoketarget) = postinvoke {
213228 // We translate the copy into a temporary block. The temporary block is
@@ -242,14 +257,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
242257 target. br ( postinvoketarget. llbb ( ) ) ;
243258 }
244259 } ,
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) ) ;
247265 bcx. unreachable ( ) ;
248266 }
249- ( false , _, _ , & Some ( ( _, target) ) ) => {
267+ ( false , _, & Some ( ( _, target) ) ) => {
250268 let llret = bcx. call ( callee. immediate ( ) ,
251269 & llargs[ ..] ,
252- None ,
270+ cleanup_bundle . as_ref ( ) ,
253271 Some ( attrs) ) ;
254272 if must_copy_dest {
255273 let ( ret_dest, ret_ty) = ret_dest_ty
@@ -258,10 +276,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
258276 base:: store_ty ( bcx, llret, ret_dest. llval , ret_ty) ;
259277 } ) ;
260278 }
261- bcx . br ( self . llblock ( target) ) ;
279+ funclet_br ( bcx , self . llblock ( target) ) ;
262280 }
263281 // Foreign functions
264- ( true , _, _ , destination) => {
282+ ( true , _, destination) => {
265283 let ( dest, _) = ret_dest_ty
266284 . expect ( "return destination is not set" ) ;
267285 bcx = bcx. map_block ( |bcx| {
@@ -274,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
274292 debugloc)
275293 } ) ;
276294 if let Some ( ( _, target) ) = * destination {
277- bcx . br ( self . llblock ( target) ) ;
295+ funclet_br ( bcx , self . llblock ( target) ) ;
278296 }
279297 } ,
280298 }
@@ -297,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
297315 }
298316 }
299317
318+ /// Create a landingpad wrapper around the given Block.
319+ ///
320+ /// No-op in MSVC SEH scheme.
300321 fn make_landing_pad ( & mut self ,
301322 cleanup : BlockAndBuilder < ' bcx , ' tcx > )
302323 -> BlockAndBuilder < ' bcx , ' tcx >
303324 {
304- // FIXME(#30941) this doesn't handle msvc-style exceptions
325+ if base:: wants_msvc_seh ( cleanup. sess ( ) ) {
326+ return cleanup;
327+ }
305328 let bcx = self . fcx . new_block ( "cleanup" , None ) . build ( ) ;
306329 let ccx = bcx. ccx ( ) ;
307330 let llpersonality = self . fcx . eh_personality ( ) ;
@@ -314,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
314337 bcx
315338 }
316339
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+
317365 fn unreachable_block ( & mut self ) -> Block < ' bcx , ' tcx > {
318366 self . unreachable_block . unwrap_or_else ( || {
319367 let bl = self . fcx . new_block ( "unreachable" , None ) ;
0 commit comments