]>
Commit | Line | Data |
---|---|---|
b7449926 | 1 | use std::borrow::Cow; |
ba9703b0 | 2 | use std::convert::TryFrom; |
b7449926 | 3 | |
17df50a5 XL |
4 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
5 | use rustc_middle::ty::layout::{self, TyAndLayout}; | |
ba9703b0 | 6 | use rustc_middle::ty::Instance; |
17df50a5 XL |
7 | use rustc_middle::{ |
8 | mir, | |
9 | ty::{self, Ty}, | |
10 | }; | |
ba9703b0 | 11 | use rustc_target::abi::{self, LayoutOf as _}; |
b7449926 XL |
12 | use rustc_target::spec::abi::Abi; |
13 | ||
b7449926 | 14 | use super::{ |
136023e0 XL |
15 | FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Scalar, |
16 | StackPopCleanup, StackPopUnwind, | |
b7449926 XL |
17 | }; |
18 | ||
ba9703b0 | 19 | impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { |
17df50a5 | 20 | fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { |
94222f64 | 21 | layout::fn_can_unwind(*self.tcx, attrs, abi) |
17df50a5 XL |
22 | } |
23 | ||
b7449926 XL |
24 | pub(super) fn eval_terminator( |
25 | &mut self, | |
26 | terminator: &mir::Terminator<'tcx>, | |
dc9dc135 | 27 | ) -> InterpResult<'tcx> { |
ba9703b0 | 28 | use rustc_middle::mir::TerminatorKind::*; |
b7449926 XL |
29 | match terminator.kind { |
30 | Return => { | |
60c5eb7d | 31 | self.pop_stack_frame(/* unwinding */ false)? |
b7449926 XL |
32 | } |
33 | ||
60c5eb7d | 34 | Goto { target } => self.go_to_block(target), |
b7449926 | 35 | |
29967ef6 | 36 | SwitchInt { ref discr, ref targets, switch_ty } => { |
6a06907d | 37 | let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; |
b7449926 | 38 | trace!("SwitchInt({:?})", *discr); |
f035d41b | 39 | assert_eq!(discr.layout.ty, switch_ty); |
b7449926 XL |
40 | |
41 | // Branch to the `otherwise` case by default, if no match is found. | |
29967ef6 XL |
42 | assert!(!targets.iter().is_empty()); |
43 | let mut target_block = targets.otherwise(); | |
b7449926 | 44 | |
29967ef6 | 45 | for (const_int, target) in targets.iter() { |
b7449926 | 46 | // Compare using binary_op, to also support pointer values |
dfeec247 XL |
47 | let res = self |
48 | .overflowing_binary_op( | |
49 | mir::BinOp::Eq, | |
6a06907d XL |
50 | &discr, |
51 | &ImmTy::from_uint(const_int, discr.layout), | |
dfeec247 XL |
52 | )? |
53 | .0; | |
b7449926 | 54 | if res.to_bool()? { |
29967ef6 | 55 | target_block = target; |
b7449926 XL |
56 | break; |
57 | } | |
58 | } | |
59 | ||
60c5eb7d | 60 | self.go_to_block(target_block); |
b7449926 XL |
61 | } |
62 | ||
f035d41b | 63 | Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => { |
ba9703b0 | 64 | let old_stack = self.frame_idx(); |
f9f354fc | 65 | let old_loc = self.frame().loc; |
b7449926 | 66 | let func = self.eval_operand(func, None)?; |
17df50a5 | 67 | let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() { |
b7449926 XL |
68 | ty::FnPtr(sig) => { |
69 | let caller_abi = sig.abi(); | |
136023e0 | 70 | let fn_ptr = self.read_pointer(&func)?; |
94222f64 | 71 | let fn_val = self.memory.get_fn(fn_ptr)?; |
17df50a5 XL |
72 | ( |
73 | fn_val, | |
74 | caller_abi, | |
94222f64 | 75 | self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi), |
17df50a5 | 76 | ) |
b7449926 XL |
77 | } |
78 | ty::FnDef(def_id, substs) => { | |
79 | let sig = func.layout.ty.fn_sig(*self.tcx); | |
1b1a35ee XL |
80 | ( |
81 | FnVal::Instance( | |
82 | self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, | |
83 | ), | |
84 | sig.abi(), | |
17df50a5 | 85 | self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()), |
1b1a35ee | 86 | ) |
b7449926 | 87 | } |
ba9703b0 XL |
88 | _ => span_bug!( |
89 | terminator.source_info.span, | |
90 | "invalid callee of type {:?}", | |
91 | func.layout.ty | |
92 | ), | |
b7449926 XL |
93 | }; |
94 | let args = self.eval_operands(args)?; | |
6a06907d | 95 | let dest_place; |
60c5eb7d | 96 | let ret = match destination { |
6a06907d XL |
97 | Some((dest, ret)) => { |
98 | dest_place = self.eval_place(dest)?; | |
99 | Some((&dest_place, ret)) | |
100 | } | |
60c5eb7d XL |
101 | None => None, |
102 | }; | |
17df50a5 XL |
103 | self.eval_fn_call( |
104 | fn_val, | |
105 | abi, | |
106 | &args[..], | |
107 | ret, | |
108 | match (cleanup, caller_can_unwind) { | |
109 | (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), | |
110 | (None, true) => StackPopUnwind::Skip, | |
111 | (_, false) => StackPopUnwind::NotAllowed, | |
112 | }, | |
113 | )?; | |
ba9703b0 XL |
114 | // Sanity-check that `eval_fn_call` either pushed a new frame or |
115 | // did a jump to another block. | |
f9f354fc | 116 | if self.frame_idx() == old_stack && self.frame().loc == old_loc { |
ba9703b0 XL |
117 | span_bug!(terminator.source_info.span, "evaluating this call made no progress"); |
118 | } | |
b7449926 XL |
119 | } |
120 | ||
f035d41b XL |
121 | Drop { place, target, unwind } => { |
122 | let place = self.eval_place(place)?; | |
b7449926 | 123 | let ty = place.layout.ty; |
f035d41b | 124 | trace!("TerminatorKind::drop: {:?}, type {}", place, ty); |
b7449926 | 125 | |
dc9dc135 | 126 | let instance = Instance::resolve_drop_in_place(*self.tcx, ty); |
6a06907d | 127 | self.drop_in_place(&place, instance, target, unwind)?; |
b7449926 XL |
128 | } |
129 | ||
dfeec247 XL |
130 | Assert { ref cond, expected, ref msg, target, cleanup } => { |
131 | let cond_val = | |
6a06907d | 132 | self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?; |
b7449926 | 133 | if expected == cond_val { |
60c5eb7d | 134 | self.go_to_block(target); |
b7449926 | 135 | } else { |
ba9703b0 | 136 | M::assert_panic(self, msg, cleanup)?; |
b7449926 XL |
137 | } |
138 | } | |
139 | ||
ba9703b0 | 140 | Abort => { |
fc512014 | 141 | M::abort(self, "the program aborted execution".to_owned())?; |
ba9703b0 XL |
142 | } |
143 | ||
60c5eb7d XL |
144 | // When we encounter Resume, we've finished unwinding |
145 | // cleanup for the current stack frame. We pop it in order | |
146 | // to continue unwinding the next frame | |
147 | Resume => { | |
148 | trace!("unwinding: resuming from cleanup"); | |
149 | // By definition, a Resume terminator means | |
150 | // that we're unwinding | |
151 | self.pop_stack_frame(/* unwinding */ true)?; | |
dfeec247 XL |
152 | return Ok(()); |
153 | } | |
60c5eb7d XL |
154 | |
155 | // It is UB to ever encounter this. | |
156 | Unreachable => throw_ub!(Unreachable), | |
157 | ||
158 | // These should never occur for MIR we actually run. | |
ba9703b0 | 159 | DropAndReplace { .. } |
f035d41b | 160 | | FalseEdge { .. } |
ba9703b0 XL |
161 | | FalseUnwind { .. } |
162 | | Yield { .. } | |
163 | | GeneratorDrop => span_bug!( | |
164 | terminator.source_info.span, | |
165 | "{:#?} should have been eliminated by MIR pass", | |
166 | terminator.kind | |
167 | ), | |
f9f354fc XL |
168 | |
169 | // Inline assembly can't be interpreted. | |
170 | InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), | |
b7449926 XL |
171 | } |
172 | ||
173 | Ok(()) | |
174 | } | |
175 | ||
176 | fn check_argument_compat( | |
a1dfa0c6 | 177 | rust_abi: bool, |
ba9703b0 XL |
178 | caller: TyAndLayout<'tcx>, |
179 | callee: TyAndLayout<'tcx>, | |
b7449926 XL |
180 | ) -> bool { |
181 | if caller.ty == callee.ty { | |
182 | // No question | |
183 | return true; | |
184 | } | |
a1dfa0c6 XL |
185 | if !rust_abi { |
186 | // Don't risk anything | |
187 | return false; | |
188 | } | |
b7449926 XL |
189 | // Compare layout |
190 | match (&caller.abi, &callee.abi) { | |
a1dfa0c6 XL |
191 | // Different valid ranges are okay (once we enforce validity, |
192 | // that will take care to make it UB to leave the range, just | |
193 | // like for transmute). | |
ba9703b0 | 194 | (abi::Abi::Scalar(ref caller), abi::Abi::Scalar(ref callee)) => { |
dfeec247 XL |
195 | caller.value == callee.value |
196 | } | |
197 | ( | |
ba9703b0 XL |
198 | abi::Abi::ScalarPair(ref caller1, ref caller2), |
199 | abi::Abi::ScalarPair(ref callee1, ref callee2), | |
dfeec247 | 200 | ) => caller1.value == callee1.value && caller2.value == callee2.value, |
b7449926 | 201 | // Be conservative |
dfeec247 | 202 | _ => false, |
b7449926 XL |
203 | } |
204 | } | |
205 | ||
206 | /// Pass a single argument, checking the types for compatibility. | |
207 | fn pass_argument( | |
208 | &mut self, | |
a1dfa0c6 | 209 | rust_abi: bool, |
dfeec247 | 210 | caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>, |
6a06907d | 211 | callee_arg: &PlaceTy<'tcx, M::PointerTag>, |
dc9dc135 | 212 | ) -> InterpResult<'tcx> { |
a1dfa0c6 | 213 | if rust_abi && callee_arg.layout.is_zst() { |
b7449926 XL |
214 | // Nothing to do. |
215 | trace!("Skipping callee ZST"); | |
216 | return Ok(()); | |
217 | } | |
ba9703b0 XL |
218 | let caller_arg = caller_arg.next().ok_or_else(|| { |
219 | err_ub_format!("calling a function with fewer arguments than it requires") | |
220 | })?; | |
a1dfa0c6 | 221 | if rust_abi { |
74b04a01 | 222 | assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); |
b7449926 XL |
223 | } |
224 | // Now, check | |
a1dfa0c6 | 225 | if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { |
ba9703b0 XL |
226 | throw_ub_format!( |
227 | "calling a function with argument of type {:?} passing data of type {:?}", | |
228 | callee_arg.layout.ty, | |
229 | caller_arg.layout.ty | |
230 | ) | |
b7449926 | 231 | } |
0bf4aa26 | 232 | // We allow some transmutes here |
6a06907d | 233 | self.copy_op_transmute(&caller_arg, callee_arg) |
b7449926 XL |
234 | } |
235 | ||
236 | /// Call this function -- pushing the stack frame and initializing the arguments. | |
237 | fn eval_fn_call( | |
238 | &mut self, | |
416331ca | 239 | fn_val: FnVal<'tcx, M::ExtraFnVal>, |
b7449926 | 240 | caller_abi: Abi, |
0bf4aa26 | 241 | args: &[OpTy<'tcx, M::PointerTag>], |
6a06907d | 242 | ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, |
17df50a5 | 243 | mut unwind: StackPopUnwind, |
dc9dc135 | 244 | ) -> InterpResult<'tcx> { |
416331ca XL |
245 | trace!("eval_fn_call: {:#?}", fn_val); |
246 | ||
247 | let instance = match fn_val { | |
248 | FnVal::Instance(instance) => instance, | |
249 | FnVal::Other(extra) => { | |
5869c6ff | 250 | return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind); |
416331ca XL |
251 | } |
252 | }; | |
b7449926 | 253 | |
17df50a5 XL |
254 | let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { |
255 | ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), | |
256 | ty::Closure(..) => Abi::RustCall, | |
257 | ty::Generator(..) => Abi::Rust, | |
258 | _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), | |
259 | }; | |
260 | ||
60c5eb7d | 261 | // ABI check |
17df50a5 | 262 | let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> { |
60c5eb7d XL |
263 | let normalize_abi = |abi| match abi { |
264 | Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => | |
dfeec247 XL |
265 | // These are all the same ABI, really. |
266 | { | |
267 | Abi::Rust | |
268 | } | |
269 | abi => abi, | |
60c5eb7d XL |
270 | }; |
271 | if normalize_abi(caller_abi) != normalize_abi(callee_abi) { | |
ba9703b0 | 272 | throw_ub_format!( |
6a06907d XL |
273 | "calling a function with ABI {} using caller ABI {}", |
274 | callee_abi.name(), | |
275 | caller_abi.name() | |
ba9703b0 | 276 | ) |
60c5eb7d | 277 | } |
17df50a5 XL |
278 | Ok(()) |
279 | }; | |
60c5eb7d | 280 | |
b7449926 XL |
281 | match instance.def { |
282 | ty::InstanceDef::Intrinsic(..) => { | |
17df50a5 XL |
283 | if M::enforce_abi(self) { |
284 | check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?; | |
285 | } | |
60c5eb7d | 286 | assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); |
ba9703b0 | 287 | M::call_intrinsic(self, instance, args, ret, unwind) |
b7449926 | 288 | } |
dfeec247 XL |
289 | ty::InstanceDef::VtableShim(..) |
290 | | ty::InstanceDef::ReifyShim(..) | |
291 | | ty::InstanceDef::ClosureOnceShim { .. } | |
292 | | ty::InstanceDef::FnPtrShim(..) | |
293 | | ty::InstanceDef::DropGlue(..) | |
294 | | ty::InstanceDef::CloneShim(..) | |
295 | | ty::InstanceDef::Item(_) => { | |
b7449926 | 296 | // We need MIR for this fn |
5869c6ff XL |
297 | let body = |
298 | match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? { | |
299 | Some(body) => body, | |
300 | None => return Ok(()), | |
301 | }; | |
b7449926 | 302 | |
17df50a5 XL |
303 | // Check against the ABI of the MIR body we are calling (not the ABI of `instance`; |
304 | // these can differ when `find_mir_or_eval_fn` does something clever like resolve | |
305 | // exported symbol names). | |
306 | let callee_def_id = body.source.def_id(); | |
307 | let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id)); | |
308 | ||
309 | if M::enforce_abi(self) { | |
310 | check_abi(callee_abi)?; | |
311 | } | |
312 | ||
313 | if !matches!(unwind, StackPopUnwind::NotAllowed) | |
314 | && !self | |
315 | .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi) | |
316 | { | |
317 | // The callee cannot unwind. | |
318 | unwind = StackPopUnwind::NotAllowed; | |
319 | } | |
320 | ||
b7449926 XL |
321 | self.push_stack_frame( |
322 | instance, | |
dc9dc135 | 323 | body, |
60c5eb7d | 324 | ret.map(|p| p.0), |
dfeec247 | 325 | StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind }, |
b7449926 XL |
326 | )?; |
327 | ||
ba9703b0 XL |
328 | // If an error is raised here, pop the frame again to get an accurate backtrace. |
329 | // To this end, we wrap it all in a `try` block. | |
330 | let res: InterpResult<'tcx> = try { | |
331 | trace!( | |
332 | "caller ABI: {:?}, args: {:#?}", | |
333 | caller_abi, | |
334 | args.iter() | |
335 | .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) | |
336 | .collect::<Vec<_>>() | |
337 | ); | |
338 | trace!( | |
339 | "spread_arg: {:?}, locals: {:#?}", | |
340 | body.spread_arg, | |
341 | body.args_iter() | |
342 | .map(|local| ( | |
343 | local, | |
344 | self.layout_of_local(self.frame(), local, None).unwrap().ty | |
345 | )) | |
346 | .collect::<Vec<_>>() | |
347 | ); | |
348 | ||
349 | // Figure out how to pass which arguments. | |
350 | // The Rust ABI is special: ZST get skipped. | |
351 | let rust_abi = match caller_abi { | |
352 | Abi::Rust | Abi::RustCall => true, | |
353 | _ => false, | |
354 | }; | |
355 | // We have two iterators: Where the arguments come from, | |
356 | // and where they go to. | |
357 | ||
358 | // For where they come from: If the ABI is RustCall, we untuple the | |
359 | // last incoming argument. These two iterators do not have the same type, | |
360 | // so to keep the code paths uniform we accept an allocation | |
361 | // (for RustCall ABI only). | |
362 | let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = | |
363 | if caller_abi == Abi::RustCall && !args.is_empty() { | |
364 | // Untuple | |
6a06907d | 365 | let (untuple_arg, args) = args.split_last().unwrap(); |
ba9703b0 XL |
366 | trace!("eval_fn_call: Will pass last argument by untupling"); |
367 | Cow::from( | |
368 | args.iter() | |
369 | .map(|&a| Ok(a)) | |
370 | .chain( | |
371 | (0..untuple_arg.layout.fields.count()) | |
372 | .map(|i| self.operand_field(untuple_arg, i)), | |
373 | ) | |
374 | .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::PointerTag>>>>( | |
375 | )?, | |
376 | ) | |
377 | } else { | |
378 | // Plain arg passing | |
379 | Cow::from(args) | |
dfeec247 | 380 | }; |
ba9703b0 XL |
381 | // Skip ZSTs |
382 | let mut caller_iter = | |
383 | caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied(); | |
384 | ||
385 | // Now we have to spread them out across the callee's locals, | |
386 | // taking into account the `spread_arg`. If we could write | |
387 | // this is a single iterator (that handles `spread_arg`), then | |
388 | // `pass_argument` would be the loop body. It takes care to | |
389 | // not advance `caller_iter` for ZSTs. | |
390 | for local in body.args_iter() { | |
391 | let dest = self.eval_place(mir::Place::from(local))?; | |
392 | if Some(local) == body.spread_arg { | |
393 | // Must be a tuple | |
394 | for i in 0..dest.layout.fields.count() { | |
6a06907d XL |
395 | let dest = self.place_field(&dest, i)?; |
396 | self.pass_argument(rust_abi, &mut caller_iter, &dest)?; | |
b7449926 | 397 | } |
ba9703b0 XL |
398 | } else { |
399 | // Normal argument | |
6a06907d | 400 | self.pass_argument(rust_abi, &mut caller_iter, &dest)?; |
b7449926 | 401 | } |
ba9703b0 XL |
402 | } |
403 | // Now we should have no more caller args | |
404 | if caller_iter.next().is_some() { | |
405 | throw_ub_format!("calling a function with more arguments than it expected") | |
406 | } | |
407 | // Don't forget to check the return type! | |
408 | if let Some((caller_ret, _)) = ret { | |
409 | let callee_ret = self.eval_place(mir::Place::return_place())?; | |
410 | if !Self::check_argument_compat( | |
411 | rust_abi, | |
412 | caller_ret.layout, | |
413 | callee_ret.layout, | |
414 | ) { | |
415 | throw_ub_format!( | |
416 | "calling a function with return type {:?} passing \ | |
417 | return place of type {:?}", | |
418 | callee_ret.layout.ty, | |
419 | caller_ret.layout.ty | |
420 | ) | |
0bf4aa26 | 421 | } |
ba9703b0 XL |
422 | } else { |
423 | let local = mir::RETURN_PLACE; | |
424 | let callee_layout = self.layout_of_local(self.frame(), local, None)?; | |
425 | if !callee_layout.abi.is_uninhabited() { | |
426 | throw_ub_format!("calling a returning function without a return place") | |
0bf4aa26 | 427 | } |
ba9703b0 XL |
428 | } |
429 | }; | |
b7449926 XL |
430 | match res { |
431 | Err(err) => { | |
ba9703b0 | 432 | self.stack_mut().pop(); |
b7449926 XL |
433 | Err(err) |
434 | } | |
ba9703b0 | 435 | Ok(()) => Ok(()), |
b7449926 XL |
436 | } |
437 | } | |
438 | // cannot use the shim here, because that will only result in infinite recursion | |
439 | ty::InstanceDef::Virtual(_, idx) => { | |
48663c56 | 440 | let mut args = args.to_vec(); |
48663c56 | 441 | // We have to implement all "object safe receivers". Currently we |
1b1a35ee | 442 | // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do |
48663c56 | 443 | // not yet support custom self types. |
1b1a35ee | 444 | // Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`. |
48663c56 XL |
445 | let receiver_place = match args[0].layout.ty.builtin_deref(true) { |
446 | Some(_) => { | |
447 | // Built-in pointer. | |
6a06907d | 448 | self.deref_operand(&args[0])? |
48663c56 XL |
449 | } |
450 | None => { | |
451 | // Unsized self. | |
136023e0 | 452 | args[0].assert_mem_place() |
48663c56 XL |
453 | } |
454 | }; | |
455 | // Find and consult vtable | |
136023e0 XL |
456 | let vtable = self.scalar_to_ptr(receiver_place.vtable()); |
457 | let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; | |
b7449926 | 458 | |
48663c56 XL |
459 | // `*mut receiver_place.layout.ty` is almost the layout that we |
460 | // want for args[0]: We have to project to field 0 because we want | |
461 | // a thin pointer. | |
462 | assert!(receiver_place.layout.is_unsized()); | |
463 | let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty); | |
94222f64 | 464 | let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0); |
48663c56 | 465 | // Adjust receiver argument. |
136023e0 XL |
466 | args[0] = OpTy::from(ImmTy::from_immediate( |
467 | Scalar::from_maybe_pointer(receiver_place.ptr, self).into(), | |
468 | this_receiver_ptr, | |
469 | )); | |
b7449926 XL |
470 | trace!("Patched self operand to {:#?}", args[0]); |
471 | // recurse with concrete function | |
136023e0 | 472 | self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind) |
b7449926 XL |
473 | } |
474 | } | |
475 | } | |
476 | ||
477 | fn drop_in_place( | |
478 | &mut self, | |
6a06907d | 479 | place: &PlaceTy<'tcx, M::PointerTag>, |
b7449926 | 480 | instance: ty::Instance<'tcx>, |
b7449926 | 481 | target: mir::BasicBlock, |
dfeec247 | 482 | unwind: Option<mir::BasicBlock>, |
dc9dc135 | 483 | ) -> InterpResult<'tcx> { |
b7449926 XL |
484 | trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); |
485 | // We take the address of the object. This may well be unaligned, which is fine | |
486 | // for us here. However, unaligned accesses will probably make the actual drop | |
487 | // implementation fail -- a problem shared by rustc. | |
488 | let place = self.force_allocation(place)?; | |
489 | ||
1b1a35ee | 490 | let (instance, place) = match place.layout.ty.kind() { |
b7449926 XL |
491 | ty::Dynamic(..) => { |
492 | // Dropping a trait object. | |
6a06907d | 493 | self.unpack_dyn_trait(&place)? |
b7449926 XL |
494 | } |
495 | _ => (instance, place), | |
496 | }; | |
497 | ||
ba9703b0 | 498 | let arg = ImmTy::from_immediate( |
136023e0 | 499 | place.to_ref(self), |
ba9703b0 XL |
500 | self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, |
501 | ); | |
b7449926 XL |
502 | |
503 | let ty = self.tcx.mk_unit(); // return type is () | |
136023e0 | 504 | let dest = MPlaceTy::dangling(self.layout_of(ty)?); |
b7449926 XL |
505 | |
506 | self.eval_fn_call( | |
416331ca | 507 | FnVal::Instance(instance), |
b7449926 | 508 | Abi::Rust, |
9fa01778 | 509 | &[arg.into()], |
6a06907d | 510 | Some((&dest.into(), target)), |
17df50a5 XL |
511 | match unwind { |
512 | Some(cleanup) => StackPopUnwind::Cleanup(cleanup), | |
513 | None => StackPopUnwind::Skip, | |
514 | }, | |
b7449926 XL |
515 | ) |
516 | } | |
517 | } |