@@ -80,12 +80,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
80
80
}
81
81
82
82
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 ) ;
86
86
build:: Resume ( bcx, lp) ;
87
87
} else {
88
- panic ! ( "resume terminator without personality slot" )
88
+ panic ! ( "resume terminator without personality slot set " )
89
89
}
90
90
}
91
91
@@ -94,33 +94,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
94
94
base:: build_return_block ( bcx. fcx , bcx, return_ty, DebugLoc :: None ) ;
95
95
}
96
96
97
- mir:: Terminator :: Call { ref data , targets } => {
97
+ mir:: Terminator :: Call { ref func , ref args , ref destination , ref targets } => {
98
98
// 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 ( ) ) ;
101
101
// Create the callee. This will always be a fn
102
102
// 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
108
112
} else {
109
- panic ! ( "trans_block: expected TyBareFn as callee" ) ;
113
+ Vec :: with_capacity ( args . len ( ) )
110
114
} ;
111
115
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
-
122
116
// Process the rest of the args.
123
- for arg in & data . args {
117
+ for arg in args {
124
118
let arg_op = self . trans_operand ( bcx, arg) ;
125
119
match arg_op. val {
126
120
Ref ( llval) | Immediate ( llval) => llargs. push ( llval) ,
@@ -132,35 +126,92 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
132
126
}
133
127
}
134
128
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
+ }
152
156
}
153
157
}
154
-
155
- build:: Br ( bcx, self . llblock ( targets. 0 ) , DebugLoc :: None )
156
158
} ,
157
159
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
+ }
160
191
}
161
192
}
162
193
}
163
194
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
+
164
215
fn unreachable_block ( & mut self ) -> Block < ' bcx , ' tcx > {
165
216
match self . unreachable_block {
166
217
Some ( b) => b,
0 commit comments