@@ -80,12 +80,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
8080 }
8181
8282 mir:: Terminator :: Resume => {
83- if let Some ( llpersonalityslot ) = self . llpersonalityslot {
84- let lp = build:: Load ( bcx, llpersonalityslot ) ;
85- // FIXME(lifetime) base::call_lifetime_end(bcx, self.personality );
83+ if let Some ( personalityslot ) = self . llpersonalityslot {
84+ let lp = build:: Load ( bcx, personalityslot ) ;
85+ base:: call_lifetime_end ( bcx, personalityslot ) ;
8686 build:: Resume ( bcx, lp) ;
8787 } else {
88- panic ! ( "resume terminator without personality slot" )
88+ panic ! ( "resume terminator without personality slot set " )
8989 }
9090 }
9191
@@ -94,33 +94,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
9494 base:: build_return_block ( bcx. fcx , bcx, return_ty, DebugLoc :: None ) ;
9595 }
9696
97- mir:: Terminator :: Call { ref data , targets } => {
97+ mir:: Terminator :: Call { ref func , ref args , ref destination , ref targets } => {
9898 // The location we'll write the result of the call into.
99- let call_dest = self . trans_lvalue ( bcx, & data . destination ) ;
100-
99+ let call_dest = self . trans_lvalue ( bcx, destination) ;
100+ let ret_ty = call_dest . ty . to_ty ( bcx . tcx ( ) ) ;
101101 // Create the callee. This will always be a fn
102102 // ptr and hence a kind of scalar.
103- let callee = self . trans_operand ( bcx, & data. func ) ;
104- let ret_ty = if let ty:: TyBareFn ( _, ref f) = callee. ty . sty {
105- let sig = bcx. tcx ( ) . erase_late_bound_regions ( & f. sig ) ;
106- let sig = infer:: normalize_associated_type ( bcx. tcx ( ) , & sig) ;
107- sig. output
103+ let callee = self . trans_operand ( bcx, func) ;
104+
105+ // Does the fn use an outptr? If so, we have an extra first argument.
106+ let return_outptr = type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) ;
107+ // The arguments we'll be passing.
108+ let mut llargs = if return_outptr {
109+ let mut vec = Vec :: with_capacity ( args. len ( ) + 1 ) ;
110+ vec. push ( call_dest. llval ) ;
111+ vec
108112 } else {
109- panic ! ( "trans_block: expected TyBareFn as callee" ) ;
113+ Vec :: with_capacity ( args . len ( ) )
110114 } ;
111115
112- // The arguments we'll be passing
113- let mut llargs = vec ! [ ] ;
114-
115- // Does the fn use an outptr? If so, that's the first arg.
116- if let ty:: FnConverging ( ret_ty) = ret_ty {
117- if type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) {
118- llargs. push ( call_dest. llval ) ;
119- }
120- }
121-
122116 // Process the rest of the args.
123- for arg in & data . args {
117+ for arg in args {
124118 let arg_op = self . trans_operand ( bcx, arg) ;
125119 match arg_op. val {
126120 Ref ( llval) | Immediate ( llval) => llargs. push ( llval) ,
@@ -132,35 +126,92 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
132126 }
133127 }
134128
135- // FIXME: Handle panics
136- //let panic_bb = self.llblock(targets.1);
137- //self.make_landing_pad(panic_bb);
138-
139- // Do the actual call.
140- let ( llret, b) = base:: invoke ( bcx,
141- callee. immediate ( ) ,
142- & llargs[ ..] ,
143- callee. ty ,
144- DebugLoc :: None ) ;
145- bcx = b;
146-
147- // Copy the return value into the destination.
148- if let ty:: FnConverging ( ret_ty) = ret_ty {
149- if !type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) &&
150- !common:: type_is_zero_size ( bcx. ccx ( ) , ret_ty) {
151- base:: store_ty ( bcx, llret, call_dest. llval , ret_ty) ;
129+ let debugloc = DebugLoc :: None ;
130+ let attrs = attributes:: from_fn_type ( bcx. ccx ( ) , callee. ty ) ;
131+ match * targets {
132+ mir:: CallTargets :: Return ( ret) => {
133+ let llret = build:: Call ( bcx,
134+ callee. immediate ( ) ,
135+ & llargs[ ..] ,
136+ Some ( attrs) ,
137+ debugloc) ;
138+ if !return_outptr && !common:: type_is_zero_size ( bcx. ccx ( ) , ret_ty) {
139+ base:: store_ty ( bcx, llret, call_dest. llval , ret_ty) ;
140+ }
141+ build:: Br ( bcx, self . llblock ( ret) , debugloc)
142+ }
143+ mir:: CallTargets :: WithCleanup ( ( ret, cleanup) ) => {
144+ let landingpad = self . make_landing_pad ( cleanup) ;
145+ build:: Invoke ( bcx,
146+ callee. immediate ( ) ,
147+ & llargs[ ..] ,
148+ self . llblock ( ret) ,
149+ landingpad. llbb ,
150+ Some ( attrs) ,
151+ debugloc) ;
152+ if !return_outptr && !common:: type_is_zero_size ( bcx. ccx ( ) , ret_ty) {
153+ // FIXME: What do we do here?
154+ unimplemented ! ( )
155+ }
152156 }
153157 }
154-
155- build:: Br ( bcx, self . llblock ( targets. 0 ) , DebugLoc :: None )
156158 } ,
157159
158- mir:: Terminator :: DivergingCall { .. } => {
159- unimplemented ! ( )
160+ mir:: Terminator :: DivergingCall { ref func, ref args, ref cleanup } => {
161+ let callee = self . trans_operand ( bcx, func) ;
162+ let mut llargs = Vec :: with_capacity ( args. len ( ) ) ;
163+ for arg in args {
164+ match self . trans_operand ( bcx, arg) . val {
165+ Ref ( llval) | Immediate ( llval) => llargs. push ( llval) ,
166+ FatPtr ( b, e) => {
167+ llargs. push ( b) ;
168+ llargs. push ( e) ;
169+ }
170+ }
171+ }
172+ let debugloc = DebugLoc :: None ;
173+ let attrs = attributes:: from_fn_type ( bcx. ccx ( ) , callee. ty ) ;
174+ match * cleanup {
175+ None => {
176+ build:: Call ( bcx, callee. immediate ( ) , & llargs[ ..] , Some ( attrs) , debugloc) ;
177+ build:: Unreachable ( bcx) ;
178+ }
179+ Some ( cleanup) => {
180+ let landingpad = self . make_landing_pad ( cleanup) ;
181+ let unreachable = self . unreachable_block ( ) ;
182+ build:: Invoke ( bcx,
183+ callee. immediate ( ) ,
184+ & llargs[ ..] ,
185+ unreachable. llbb ,
186+ landingpad. llbb ,
187+ Some ( attrs) ,
188+ debugloc) ;
189+ }
190+ }
160191 }
161192 }
162193 }
163194
195+ fn make_landing_pad ( & mut self , cleanup : mir:: BasicBlock ) -> Block < ' bcx , ' tcx > {
196+ let bcx = self . bcx ( cleanup) . fcx . new_block ( true , "cleanup" , None ) ;
197+ let ccx = bcx. ccx ( ) ;
198+ let llpersonality = bcx. fcx . eh_personality ( ) ;
199+ let llretty = Type :: struct_ ( ccx, & [ Type :: i8p ( ccx) , Type :: i32 ( ccx) ] , false ) ;
200+ let llretval = build:: LandingPad ( bcx, llretty, llpersonality, 1 ) ;
201+ build:: SetCleanup ( bcx, llretval) ;
202+ match self . llpersonalityslot {
203+ Some ( slot) => build:: Store ( bcx, llretval, slot) ,
204+ None => {
205+ let personalityslot = base:: alloca ( bcx, llretty, "personalityslot" ) ;
206+ self . llpersonalityslot = Some ( personalityslot) ;
207+ base:: call_lifetime_start ( bcx, personalityslot) ;
208+ build:: Store ( bcx, llretval, personalityslot)
209+ }
210+ } ;
211+ build:: Br ( bcx, self . llblock ( cleanup) , DebugLoc :: None ) ;
212+ bcx
213+ }
214+
164215 fn unreachable_block ( & mut self ) -> Block < ' bcx , ' tcx > {
165216 match self . unreachable_block {
166217 Some ( b) => b,
0 commit comments